diff --git a/jstests/aggregation/sources/bucket/collation_bucket.js b/jstests/aggregation/sources/bucket/collation_bucket.js index 4171e19c429..3bb0f32b10a 100644 --- a/jstests/aggregation/sources/bucket/collation_bucket.js +++ b/jstests/aggregation/sources/bucket/collation_bucket.js @@ -1,16 +1,7 @@ // Cannot implicitly shard accessed collections because of collection existing when none expected. // @tags: [assumes_no_implicit_collection_creation_after_drop] -// Test that the $bucket stage defines and sorts buckets according to the collation. -let results; -const numericOrdering = { - collation: {locale: "en_US", numericOrdering: true}, -}; - -let coll = db.collation_bucket; -coll.drop(); - -function insertData() { +const insertData = (coll) => { assert.commandWorked(coll.insert({num: "1"})); assert.commandWorked(coll.insert({num: "2"})); assert.commandWorked(coll.insert({num: "5"})); @@ -20,88 +11,112 @@ function insertData() { assert.commandWorked(coll.insert({num: "100"})); assert.commandWorked(coll.insert({num: "200"})); assert.commandWorked(coll.insert({num: "500"})); -} +}; -insertData(); +// Test that the $bucket stage defines and sorts buckets according to the collation. +const numericOrdering = { + collation: {locale: "en_US", numericOrdering: true}, +}; -// Test that $bucket respects an explicit collation. -results = coll - .aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}], numericOrdering) - .toArray(); -assert.eq(3, results.length); -assert.eq({_id: "1", count: 3}, results[0]); -assert.eq({_id: "10", count: 3}, results[1]); -assert.eq({_id: "100", count: 3}, results[2]); +// Run test on a collection without any collation. The collation is passed to the aggregate query instead. +const runTestCollectionNoCollation = () => { + const coll = db.collation_bucket; + coll.drop(); -coll.drop(); -assert.commandWorked(db.createCollection(coll.getName(), numericOrdering)); -insertData(); + insertData(coll); -// Test that $bucket respects the inherited collation. -results = coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}]).toArray(); -assert.eq(3, results.length); -assert.eq({_id: "1", count: 3}, results[0]); -assert.eq({_id: "10", count: 3}, results[1]); -assert.eq({_id: "100", count: 3}, results[2]); + const results = coll + .aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}], numericOrdering) + .toArray(); + assert.eq(3, results.length); + assert.eq({_id: "1", count: 3}, results[0]); + assert.eq({_id: "10", count: 3}, results[1]); + assert.eq({_id: "100", count: 3}, results[2]); -// Test that the collection default can be overridden with the simple collation. In this case, -// the $bucket should fail, because under a lexicographical comparison strings like "2" or "5" -// won't fall into any of the buckets. -assert.throws(() => - coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}], { - collation: {locale: "simple"}, - }), -); + coll.drop(); +}; -// Test that $bucket rejects boundaries that are not sorted according to the collation. -assert.throws(() => coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["100", "20", "4"]}}])); +// Run test on a collection with a collation. +const runTestCollectionWithCollation = () => { + // The collection is recreated using a different name to avoid problems with outdated router + // caches in multi-router setups. + const coll = db.collation_bucket_collation; + coll.drop(); + assert.commandWorked(db.createCollection(coll.getName(), numericOrdering)); -assert.throws(() => - coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["4", "20", "100"]}}], {collation: {locale: "simple"}}), -); + insertData(coll); -// Test that $bucket rejects a default value that falls within the boundaries. -assert.throws(() => coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100"], default: "40"}}])); + // Test that $bucket respects the inherited collation. + let results = coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}]).toArray(); + assert.eq(3, results.length); + assert.eq({_id: "1", count: 3}, results[0]); + assert.eq({_id: "10", count: 3}, results[1]); + assert.eq({_id: "100", count: 3}, results[2]); -assert.throws(() => - coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["100", "999"], default: "2"}}], { - collation: {locale: "simple"}, - }), -); + // Test that the collection default can be overridden with the simple collation. In this case, + // the $bucket should fail, because under a lexicographical comparison strings like "2" or "5" + // won't fall into any of the buckets. + assert.throws(() => + coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100", "1000"]}}], { + collation: {locale: "simple"}, + }), + ); -// Test that $bucket accepts a default value that falls outside the boundaries according to the -// collation. -results = coll - .aggregate([ - { - $bucket: { - groupBy: "$num", - boundaries: ["100", "999"], - default: "2", // Would fall between 100 and 999 if using the simple collation. - }, - }, - ]) - .toArray(); -assert.eq(2, results.length); -assert.eq({_id: "2", count: 6}, results[0]); -assert.eq({_id: "100", count: 3}, results[1]); // "100", "200", and "500". + // Test that $bucket rejects boundaries that are not sorted according to the collation. + assert.throws(() => coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["100", "20", "4"]}}])); -results = coll - .aggregate( - [ + assert.throws(() => + coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["4", "20", "100"]}}], {collation: {locale: "simple"}}), + ); + + // Test that $bucket rejects a default value that falls within the boundaries. + assert.throws(() => coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["1", "10", "100"], default: "40"}}])); + + assert.throws(() => + coll.aggregate([{$bucket: {groupBy: "$num", boundaries: ["100", "999"], default: "2"}}], { + collation: {locale: "simple"}, + }), + ); + + // Test that $bucket accepts a default value that falls outside the boundaries according to the + // collation. + results = coll + .aggregate([ { $bucket: { groupBy: "$num", - boundaries: ["1", "19999"], // Will include all numbers that start with "1" - default: "2", // Would fall between boundaries if using the - // collection-default collation with numeric - // ordering. + boundaries: ["100", "999"], + default: "2", // Would fall between 100 and 999 if using the simple collation. }, }, - ], - {collation: {locale: "simple"}}, - ) - .toArray(); -assert.eq(2, results.length); -assert.eq({_id: "1", count: 3}, results[0]); // "1", "10", and "100". -assert.eq({_id: "2", count: 6}, results[1]); + ]) + .toArray(); + assert.eq(2, results.length); + assert.eq({_id: "2", count: 6}, results[0]); + assert.eq({_id: "100", count: 3}, results[1]); // "100", "200", and "500". + + results = coll + .aggregate( + [ + { + $bucket: { + groupBy: "$num", + boundaries: ["1", "19999"], // Will include all numbers that start with "1" + default: "2", // Would fall between boundaries if using the + // collection-default collation with numeric + // ordering. + }, + }, + ], + {collation: {locale: "simple"}}, + ) + .toArray(); + assert.eq(2, results.length); + assert.eq({_id: "1", count: 3}, results[0]); // "1", "10", and "100". + assert.eq({_id: "2", count: 6}, results[1]); + + coll.drop(); +}; + +runTestCollectionNoCollation(); +runTestCollectionWithCollation();