diff options
Diffstat (limited to 'jstests/sharding/collation_targeting.js')
-rw-r--r-- | jstests/sharding/collation_targeting.js | 843 |
1 files changed, 423 insertions, 420 deletions
diff --git a/jstests/sharding/collation_targeting.js b/jstests/sharding/collation_targeting.js index fc2b9c193eb..c58396eaa80 100644 --- a/jstests/sharding/collation_targeting.js +++ b/jstests/sharding/collation_targeting.js @@ -1,462 +1,465 @@ // Test shard targeting for queries with collation. (function() { - "use strict"; - - const caseInsensitive = {locale: "en_US", strength: 2}; - - var explain; - var writeRes; - - // Create a cluster with 3 shards. - var st = new ShardingTest({shards: 3}); - var testDB = st.s.getDB("test"); - assert.commandWorked(testDB.adminCommand({enableSharding: testDB.getName()})); - st.ensurePrimaryShard(testDB.getName(), st.shard1.shardName); - - // Create a collection sharded on {a: 1}. Add 2dsphere index to test $geoNear. - var coll = testDB.getCollection("simple_collation"); - coll.drop(); - assert.commandWorked(coll.createIndex({a: 1})); - assert.commandWorked(coll.createIndex({geo: "2dsphere"})); - assert.commandWorked(testDB.adminCommand({shardCollection: coll.getFullName(), key: {a: 1}})); - - // Split the collection. - // st.shard0.shardName: { "a" : { "$minKey" : 1 } } -->> { "a" : 10 } - // st.shard1.shardName: { "a" : 10 } -->> { "a" : "a"} - // shard0002: { "a" : "a" } -->> { "a" : { "$maxKey" : 1 }} - assert.commandWorked(testDB.adminCommand({split: coll.getFullName(), middle: {a: 10}})); - assert.commandWorked(testDB.adminCommand({split: coll.getFullName(), middle: {a: "a"}})); - assert.commandWorked(testDB.adminCommand( - {moveChunk: coll.getFullName(), find: {a: 1}, to: st.shard0.shardName})); - assert.commandWorked(testDB.adminCommand( - {moveChunk: coll.getFullName(), find: {a: "FOO"}, to: st.shard1.shardName})); - assert.commandWorked(testDB.adminCommand( - {moveChunk: coll.getFullName(), find: {a: "foo"}, to: st.shard2.shardName})); - - // Put data on each shard. - // Note that the balancer is off by default, so the chunks will stay put. - // st.shard0.shardName: {a: 1} - // st.shard1.shardName: {a: 100}, {a: "FOO"} - // shard0002: {a: "foo"} - // Include geo field to test $geoNear. - var a_1 = {_id: 0, a: 1, geo: {type: "Point", coordinates: [0, 0]}}; - var a_100 = {_id: 1, a: 100, geo: {type: "Point", coordinates: [0, 0]}}; - var a_FOO = {_id: 2, a: "FOO", geo: {type: "Point", coordinates: [0, 0]}}; - var a_foo = {_id: 3, a: "foo", geo: {type: "Point", coordinates: [0, 0]}}; - assert.writeOK(coll.insert(a_1)); - assert.writeOK(coll.insert(a_100)); - assert.writeOK(coll.insert(a_FOO)); - assert.writeOK(coll.insert(a_foo)); - - // Aggregate. - - // Test an aggregate command on strings with a non-simple collation. This should be - // scatter-gather. - assert.eq(2, coll.aggregate([{$match: {a: "foo"}}], {collation: caseInsensitive}).itcount()); - explain = coll.explain().aggregate([{$match: {a: "foo"}}], {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(3, Object.keys(explain.shards).length); - - // Test an aggregate command with a simple collation. This should be single-shard. - assert.eq(1, coll.aggregate([{$match: {a: "foo"}}]).itcount()); - explain = coll.explain().aggregate([{$match: {a: "foo"}}]); - assert.commandWorked(explain); - assert.eq(1, Object.keys(explain.shards).length); - - // Test an aggregate command on numbers with a non-simple collation. This should be - // single-shard. - assert.eq(1, coll.aggregate([{$match: {a: 100}}], {collation: caseInsensitive}).itcount()); - explain = coll.explain().aggregate([{$match: {a: 100}}], {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, Object.keys(explain.shards).length); - - // Aggregate with $geoNear. - const geoJSONPoint = {type: "Point", coordinates: [0, 0]}; - - // Test $geoNear with a query on strings with a non-simple collation. This should - // scatter-gather. - const geoNearStageStringQuery = [{ - $geoNear: { - near: geoJSONPoint, - distanceField: "dist", - spherical: true, - query: {a: "foo"}, - } - }]; - assert.eq(2, coll.aggregate(geoNearStageStringQuery, {collation: caseInsensitive}).itcount()); - explain = coll.explain().aggregate(geoNearStageStringQuery, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(3, Object.keys(explain.shards).length); - - // Test $geoNear with a query on strings with a simple collation. This should be single-shard. - assert.eq(1, coll.aggregate(geoNearStageStringQuery).itcount()); - explain = coll.explain().aggregate(geoNearStageStringQuery); - assert.commandWorked(explain); - assert.eq(1, Object.keys(explain.shards).length); - - // Test a $geoNear with a query on numbers with a non-simple collation. This should be - // single-shard. - const geoNearStageNumericalQuery = [{ - $geoNear: { - near: geoJSONPoint, - distanceField: "dist", - spherical: true, - query: {a: 100}, - } - }]; - assert.eq(1, - coll.aggregate(geoNearStageNumericalQuery, {collation: caseInsensitive}).itcount()); - explain = coll.explain().aggregate(geoNearStageNumericalQuery, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, Object.keys(explain.shards).length); - - // Count. - - // Test a count command on strings with a non-simple collation. This should be scatter-gather. - assert.eq(2, coll.find({a: "foo"}).collation(caseInsensitive).count()); - explain = coll.explain().find({a: "foo"}).collation(caseInsensitive).count(); +"use strict"; + +const caseInsensitive = { + locale: "en_US", + strength: 2 +}; + +var explain; +var writeRes; + +// Create a cluster with 3 shards. +var st = new ShardingTest({shards: 3}); +var testDB = st.s.getDB("test"); +assert.commandWorked(testDB.adminCommand({enableSharding: testDB.getName()})); +st.ensurePrimaryShard(testDB.getName(), st.shard1.shardName); + +// Create a collection sharded on {a: 1}. Add 2dsphere index to test $geoNear. +var coll = testDB.getCollection("simple_collation"); +coll.drop(); +assert.commandWorked(coll.createIndex({a: 1})); +assert.commandWorked(coll.createIndex({geo: "2dsphere"})); +assert.commandWorked(testDB.adminCommand({shardCollection: coll.getFullName(), key: {a: 1}})); + +// Split the collection. +// st.shard0.shardName: { "a" : { "$minKey" : 1 } } -->> { "a" : 10 } +// st.shard1.shardName: { "a" : 10 } -->> { "a" : "a"} +// shard0002: { "a" : "a" } -->> { "a" : { "$maxKey" : 1 }} +assert.commandWorked(testDB.adminCommand({split: coll.getFullName(), middle: {a: 10}})); +assert.commandWorked(testDB.adminCommand({split: coll.getFullName(), middle: {a: "a"}})); +assert.commandWorked( + testDB.adminCommand({moveChunk: coll.getFullName(), find: {a: 1}, to: st.shard0.shardName})); +assert.commandWorked(testDB.adminCommand( + {moveChunk: coll.getFullName(), find: {a: "FOO"}, to: st.shard1.shardName})); +assert.commandWorked(testDB.adminCommand( + {moveChunk: coll.getFullName(), find: {a: "foo"}, to: st.shard2.shardName})); + +// Put data on each shard. +// Note that the balancer is off by default, so the chunks will stay put. +// st.shard0.shardName: {a: 1} +// st.shard1.shardName: {a: 100}, {a: "FOO"} +// shard0002: {a: "foo"} +// Include geo field to test $geoNear. +var a_1 = {_id: 0, a: 1, geo: {type: "Point", coordinates: [0, 0]}}; +var a_100 = {_id: 1, a: 100, geo: {type: "Point", coordinates: [0, 0]}}; +var a_FOO = {_id: 2, a: "FOO", geo: {type: "Point", coordinates: [0, 0]}}; +var a_foo = {_id: 3, a: "foo", geo: {type: "Point", coordinates: [0, 0]}}; +assert.writeOK(coll.insert(a_1)); +assert.writeOK(coll.insert(a_100)); +assert.writeOK(coll.insert(a_FOO)); +assert.writeOK(coll.insert(a_foo)); + +// Aggregate. + +// Test an aggregate command on strings with a non-simple collation. This should be +// scatter-gather. +assert.eq(2, coll.aggregate([{$match: {a: "foo"}}], {collation: caseInsensitive}).itcount()); +explain = coll.explain().aggregate([{$match: {a: "foo"}}], {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(3, Object.keys(explain.shards).length); + +// Test an aggregate command with a simple collation. This should be single-shard. +assert.eq(1, coll.aggregate([{$match: {a: "foo"}}]).itcount()); +explain = coll.explain().aggregate([{$match: {a: "foo"}}]); +assert.commandWorked(explain); +assert.eq(1, Object.keys(explain.shards).length); + +// Test an aggregate command on numbers with a non-simple collation. This should be +// single-shard. +assert.eq(1, coll.aggregate([{$match: {a: 100}}], {collation: caseInsensitive}).itcount()); +explain = coll.explain().aggregate([{$match: {a: 100}}], {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(1, Object.keys(explain.shards).length); + +// Aggregate with $geoNear. +const geoJSONPoint = { + type: "Point", + coordinates: [0, 0] +}; + +// Test $geoNear with a query on strings with a non-simple collation. This should +// scatter-gather. +const geoNearStageStringQuery = [{ + $geoNear: { + near: geoJSONPoint, + distanceField: "dist", + spherical: true, + query: {a: "foo"}, + } +}]; +assert.eq(2, coll.aggregate(geoNearStageStringQuery, {collation: caseInsensitive}).itcount()); +explain = coll.explain().aggregate(geoNearStageStringQuery, {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(3, Object.keys(explain.shards).length); + +// Test $geoNear with a query on strings with a simple collation. This should be single-shard. +assert.eq(1, coll.aggregate(geoNearStageStringQuery).itcount()); +explain = coll.explain().aggregate(geoNearStageStringQuery); +assert.commandWorked(explain); +assert.eq(1, Object.keys(explain.shards).length); + +// Test a $geoNear with a query on numbers with a non-simple collation. This should be +// single-shard. +const geoNearStageNumericalQuery = [{ + $geoNear: { + near: geoJSONPoint, + distanceField: "dist", + spherical: true, + query: {a: 100}, + } +}]; +assert.eq(1, coll.aggregate(geoNearStageNumericalQuery, {collation: caseInsensitive}).itcount()); +explain = coll.explain().aggregate(geoNearStageNumericalQuery, {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(1, Object.keys(explain.shards).length); + +// Count. + +// Test a count command on strings with a non-simple collation. This should be scatter-gather. +assert.eq(2, coll.find({a: "foo"}).collation(caseInsensitive).count()); +explain = coll.explain().find({a: "foo"}).collation(caseInsensitive).count(); +assert.commandWorked(explain); +assert.eq(3, explain.queryPlanner.winningPlan.shards.length); + +// Test a count command with a simple collation. This should be single-shard. +assert.eq(1, coll.find({a: "foo"}).count()); +explain = coll.explain().find({a: "foo"}).count(); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Test a count command on numbers with a non-simple collation. This should be single-shard. +assert.eq(1, coll.find({a: 100}).collation(caseInsensitive).count()); +explain = coll.explain().find({a: 100}).collation(caseInsensitive).count(); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Distinct. + +// Test a distinct command on strings with a non-simple collation. This should be +// scatter-gather. +assert.eq(2, coll.distinct("_id", {a: "foo"}, {collation: caseInsensitive}).length); +explain = coll.explain().distinct("_id", {a: "foo"}, {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(3, explain.queryPlanner.winningPlan.shards.length); + +// Test that deduping respects the collation. +assert.eq(1, coll.distinct("a", {a: "foo"}, {collation: caseInsensitive}).length); + +// Test a distinct command with a simple collation. This should be single-shard. +assert.eq(1, coll.distinct("_id", {a: "foo"}).length); +explain = coll.explain().distinct("_id", {a: "foo"}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Test a distinct command on numbers with a non-simple collation. This should be single-shard. +assert.eq(1, coll.distinct("_id", {a: 100}, {collation: caseInsensitive}).length); +explain = coll.explain().distinct("_id", {a: 100}, {collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Find. + +// Test a find command on strings with a non-simple collation. This should be scatter-gather. +if (testDB.getMongo().useReadCommands()) { + assert.eq(2, coll.find({a: "foo"}).collation(caseInsensitive).itcount()); + explain = coll.find({a: "foo"}).collation(caseInsensitive).explain(); assert.commandWorked(explain); assert.eq(3, explain.queryPlanner.winningPlan.shards.length); - - // Test a count command with a simple collation. This should be single-shard. - assert.eq(1, coll.find({a: "foo"}).count()); - explain = coll.explain().find({a: "foo"}).count(); +} + +// Test a find command with a simple collation. This should be single-shard. +assert.eq(1, coll.find({a: "foo"}).itcount()); +explain = coll.find({a: "foo"}).explain(); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Test a find command on numbers with a non-simple collation. This should be single-shard. +if (testDB.getMongo().useReadCommands()) { + assert.eq(1, coll.find({a: 100}).collation(caseInsensitive).itcount()); + explain = coll.find({a: 100}).collation(caseInsensitive).explain(); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Test a count command on numbers with a non-simple collation. This should be single-shard. - assert.eq(1, coll.find({a: 100}).collation(caseInsensitive).count()); - explain = coll.explain().find({a: 100}).collation(caseInsensitive).count(); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Distinct. - - // Test a distinct command on strings with a non-simple collation. This should be - // scatter-gather. - assert.eq(2, coll.distinct("_id", {a: "foo"}, {collation: caseInsensitive}).length); - explain = coll.explain().distinct("_id", {a: "foo"}, {collation: caseInsensitive}); +} + +// FindAndModify. + +// Sharded findAndModify on strings with non-simple collation should fail, because findAndModify +// must target a single shard. +assert.throws(function() { + coll.findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}, collation: caseInsensitive}); +}); +assert.throws(function() { + coll.explain().findAndModify( + {query: {a: "foo"}, update: {$set: {b: 1}}, collation: caseInsensitive}); +}); + +// Sharded findAndModify on strings with simple collation should succeed. This should be +// single-shard. +assert.eq("foo", coll.findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}}).a); +explain = coll.explain().findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Sharded findAndModify on numbers with non-simple collation should succeed. This should be +// single-shard. +assert.eq( + 100, + coll.findAndModify({query: {a: 100}, update: {$set: {b: 1}}, collation: caseInsensitive}).a); +explain = coll.explain().findAndModify( + {query: {a: 100}, update: {$set: {b: 1}}, collation: caseInsensitive}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// MapReduce. + +// Test mapReduce on strings with a non-simple collation. +assert.eq(2, + assert + .commandWorked(coll.mapReduce( + function() { + emit(this.a, 1); + }, + function(key, values) { + return Array.sum(values); + }, + {out: {inline: 1}, query: {a: "foo"}, collation: caseInsensitive})) + .results.length); + +// Test mapReduce on strings with a simple collation. +assert.eq(1, + assert + .commandWorked(coll.mapReduce( + function() { + emit(this.a, 1); + }, + function(key, values) { + return Array.sum(values); + }, + {out: {inline: 1}, query: {a: "foo"}})) + .results.length); + +// Remove. + +// Test a remove command on strings with non-simple collation. This should be scatter-gather. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.remove({a: "foo"}, {collation: caseInsensitive}); + assert.writeOK(writeRes); + assert.eq(2, writeRes.nRemoved); + explain = coll.explain().remove({a: "foo"}, {collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(3, explain.queryPlanner.winningPlan.shards.length); - - // Test that deduping respects the collation. - assert.eq(1, coll.distinct("a", {a: "foo"}, {collation: caseInsensitive}).length); - - // Test a distinct command with a simple collation. This should be single-shard. - assert.eq(1, coll.distinct("_id", {a: "foo"}).length); - explain = coll.explain().distinct("_id", {a: "foo"}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Test a distinct command on numbers with a non-simple collation. This should be single-shard. - assert.eq(1, coll.distinct("_id", {a: 100}, {collation: caseInsensitive}).length); - explain = coll.explain().distinct("_id", {a: 100}, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Find. - - // Test a find command on strings with a non-simple collation. This should be scatter-gather. - if (testDB.getMongo().useReadCommands()) { - assert.eq(2, coll.find({a: "foo"}).collation(caseInsensitive).itcount()); - explain = coll.find({a: "foo"}).collation(caseInsensitive).explain(); - assert.commandWorked(explain); - assert.eq(3, explain.queryPlanner.winningPlan.shards.length); - } - - // Test a find command with a simple collation. This should be single-shard. - assert.eq(1, coll.find({a: "foo"}).itcount()); - explain = coll.find({a: "foo"}).explain(); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Test a find command on numbers with a non-simple collation. This should be single-shard. - if (testDB.getMongo().useReadCommands()) { - assert.eq(1, coll.find({a: 100}).collation(caseInsensitive).itcount()); - explain = coll.find({a: 100}).collation(caseInsensitive).explain(); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - } - - // FindAndModify. - - // Sharded findAndModify on strings with non-simple collation should fail, because findAndModify - // must target a single shard. - assert.throws(function() { - coll.findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}, collation: caseInsensitive}); - }); - assert.throws(function() { - coll.explain().findAndModify( - {query: {a: "foo"}, update: {$set: {b: 1}}, collation: caseInsensitive}); - }); - - // Sharded findAndModify on strings with simple collation should succeed. This should be - // single-shard. - assert.eq("foo", coll.findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}}).a); - explain = coll.explain().findAndModify({query: {a: "foo"}, update: {$set: {b: 1}}}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Sharded findAndModify on numbers with non-simple collation should succeed. This should be - // single-shard. - assert.eq( - 100, - coll.findAndModify({query: {a: 100}, update: {$set: {b: 1}}, collation: caseInsensitive}) - .a); - explain = coll.explain().findAndModify( - {query: {a: 100}, update: {$set: {b: 1}}, collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // MapReduce. - - // Test mapReduce on strings with a non-simple collation. - assert.eq(2, - assert - .commandWorked(coll.mapReduce( - function() { - emit(this.a, 1); - }, - function(key, values) { - return Array.sum(values); - }, - {out: {inline: 1}, query: {a: "foo"}, collation: caseInsensitive})) - .results.length); - - // Test mapReduce on strings with a simple collation. - assert.eq(1, - assert - .commandWorked(coll.mapReduce( - function() { - emit(this.a, 1); - }, - function(key, values) { - return Array.sum(values); - }, - {out: {inline: 1}, query: {a: "foo"}})) - .results.length); - - // Remove. - - // Test a remove command on strings with non-simple collation. This should be scatter-gather. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.remove({a: "foo"}, {collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(2, writeRes.nRemoved); - explain = coll.explain().remove({a: "foo"}, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(3, explain.queryPlanner.winningPlan.shards.length); - assert.writeOK(coll.insert(a_FOO)); - assert.writeOK(coll.insert(a_foo)); - } - - // Test a remove command on strings with simple collation. This should be single-shard. - writeRes = coll.remove({a: "foo"}); + assert.writeOK(coll.insert(a_FOO)); + assert.writeOK(coll.insert(a_foo)); +} + +// Test a remove command on strings with simple collation. This should be single-shard. +writeRes = coll.remove({a: "foo"}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nRemoved); +explain = coll.explain().remove({a: "foo"}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); +assert.writeOK(coll.insert(a_foo)); + +// Test a remove command on numbers with non-simple collation. This should be single-shard. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.remove({a: 100}, {collation: caseInsensitive}); assert.writeOK(writeRes); assert.eq(1, writeRes.nRemoved); - explain = coll.explain().remove({a: "foo"}); + explain = coll.explain().remove({a: 100}, {collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - assert.writeOK(coll.insert(a_foo)); - - // Test a remove command on numbers with non-simple collation. This should be single-shard. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.remove({a: 100}, {collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nRemoved); - explain = coll.explain().remove({a: 100}, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - assert.writeOK(coll.insert(a_100)); - } - - // A single remove (justOne: true) must be single-shard or an exact-ID query. A query is - // exact-ID if it contains an equality on _id and either has the collection default collation or - // _id is not a string/object/array. - - // Single remove on string shard key with non-simple collation should fail, because it is not - // single-shard. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeError(coll.remove({a: "foo"}, {justOne: true, collation: caseInsensitive})); - } - - // Single remove on string shard key with simple collation should succeed, because it is - // single-shard. - writeRes = coll.remove({a: "foo"}, {justOne: true}); + assert.writeOK(coll.insert(a_100)); +} + +// A single remove (justOne: true) must be single-shard or an exact-ID query. A query is +// exact-ID if it contains an equality on _id and either has the collection default collation or +// _id is not a string/object/array. + +// Single remove on string shard key with non-simple collation should fail, because it is not +// single-shard. +if (testDB.getMongo().writeMode() === "commands") { + assert.writeError(coll.remove({a: "foo"}, {justOne: true, collation: caseInsensitive})); +} + +// Single remove on string shard key with simple collation should succeed, because it is +// single-shard. +writeRes = coll.remove({a: "foo"}, {justOne: true}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nRemoved); +explain = coll.explain().remove({a: "foo"}, {justOne: true}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); +assert.writeOK(coll.insert(a_foo)); + +// Single remove on number shard key with non-simple collation should succeed, because it is +// single-shard. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.remove({a: 100}, {justOne: true, collation: caseInsensitive}); assert.writeOK(writeRes); assert.eq(1, writeRes.nRemoved); - explain = coll.explain().remove({a: "foo"}, {justOne: true}); + explain = coll.explain().remove({a: 100}, {justOne: true, collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - assert.writeOK(coll.insert(a_foo)); - - // Single remove on number shard key with non-simple collation should succeed, because it is - // single-shard. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.remove({a: 100}, {justOne: true, collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nRemoved); - explain = coll.explain().remove({a: 100}, {justOne: true, collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - assert.writeOK(coll.insert(a_100)); - } - - // Single remove on string _id with non-collection-default collation should fail, because it is - // not an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeError(coll.remove({_id: "foo"}, {justOne: true, collation: caseInsensitive})); - } - - // Single remove on string _id with collection-default collation should succeed, because it is - // an exact-ID query. + assert.writeOK(coll.insert(a_100)); +} + +// Single remove on string _id with non-collection-default collation should fail, because it is +// not an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { + assert.writeError(coll.remove({_id: "foo"}, {justOne: true, collation: caseInsensitive})); +} + +// Single remove on string _id with collection-default collation should succeed, because it is +// an exact-ID query. +assert.writeOK(coll.insert({_id: "foo", a: "bar"})); +writeRes = coll.remove({_id: "foo"}, {justOne: true}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nRemoved); + +// Single remove on string _id with collection-default collation explicitly given should +// succeed, because it is an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { assert.writeOK(coll.insert({_id: "foo", a: "bar"})); - writeRes = coll.remove({_id: "foo"}, {justOne: true}); + writeRes = coll.remove({_id: "foo"}, {justOne: true, collation: {locale: "simple"}}); assert.writeOK(writeRes); assert.eq(1, writeRes.nRemoved); +} - // Single remove on string _id with collection-default collation explicitly given should - // succeed, because it is an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeOK(coll.insert({_id: "foo", a: "bar"})); - writeRes = coll.remove({_id: "foo"}, {justOne: true, collation: {locale: "simple"}}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nRemoved); - } - - // Single remove on number _id with non-collection-default collation should succeed, because it - // is an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.remove({_id: a_100._id}, {justOne: true, collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nRemoved); - assert.writeOK(coll.insert(a_100)); - } +// Single remove on number _id with non-collection-default collation should succeed, because it +// is an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.remove({_id: a_100._id}, {justOne: true, collation: caseInsensitive}); + assert.writeOK(writeRes); + assert.eq(1, writeRes.nRemoved); + assert.writeOK(coll.insert(a_100)); +} - // Update. - - // Test an update command on strings with non-simple collation. This should be scatter-gather. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = - coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(2, writeRes.nMatched); - explain = coll.explain().update( - {a: "foo"}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(3, explain.queryPlanner.winningPlan.shards.length); - } +// Update. - // Test an update command on strings with simple collation. This should be single-shard. - writeRes = coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true}); +// Test an update command on strings with non-simple collation. This should be scatter-gather. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); + assert.writeOK(writeRes); + assert.eq(2, writeRes.nMatched); + explain = coll.explain().update( + {a: "foo"}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); + assert.commandWorked(explain); + assert.eq(3, explain.queryPlanner.winningPlan.shards.length); +} + +// Test an update command on strings with simple collation. This should be single-shard. +writeRes = coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nMatched); +explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}, {multi: true}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Test an update command on numbers with non-simple collation. This should be single-shard. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.update({a: 100}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); assert.writeOK(writeRes); assert.eq(1, writeRes.nMatched); - explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}, {multi: true}); + explain = + coll.explain().update({a: 100}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - - // Test an update command on numbers with non-simple collation. This should be single-shard. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.update({a: 100}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nMatched); - explain = coll.explain().update( - {a: 100}, {$set: {b: 1}}, {multi: true, collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - } - - // A single (non-multi) update must be single-shard or an exact-ID query. A query is exact-ID if - // it contains an equality on _id and either has the collection default collation or _id is not - // a string/object/array. - - // Single update on string shard key with non-simple collation should fail, because it is not - // single-shard. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeError(coll.update({a: "foo"}, {$set: {b: 1}}, {collation: caseInsensitive})); - } - - // Single update on string shard key with simple collation should succeed, because it is - // single-shard. - writeRes = coll.update({a: "foo"}, {$set: {b: 1}}); +} + +// A single (non-multi) update must be single-shard or an exact-ID query. A query is exact-ID if +// it contains an equality on _id and either has the collection default collation or _id is not +// a string/object/array. + +// Single update on string shard key with non-simple collation should fail, because it is not +// single-shard. +if (testDB.getMongo().writeMode() === "commands") { + assert.writeError(coll.update({a: "foo"}, {$set: {b: 1}}, {collation: caseInsensitive})); +} + +// Single update on string shard key with simple collation should succeed, because it is +// single-shard. +writeRes = coll.update({a: "foo"}, {$set: {b: 1}}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nMatched); +explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Single update on number shard key with non-simple collation should succeed, because it is +// single-shard. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.update({a: 100}, {$set: {b: 1}}, {collation: caseInsensitive}); assert.writeOK(writeRes); assert.eq(1, writeRes.nMatched); - explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}); + explain = coll.explain().update({a: 100}, {$set: {b: 1}}, {collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); +} - // Single update on number shard key with non-simple collation should succeed, because it is - // single-shard. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.update({a: 100}, {$set: {b: 1}}, {collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nMatched); - explain = coll.explain().update({a: 100}, {$set: {b: 1}}, {collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - } - - // Single update on string _id with non-collection-default collation should fail, because it is - // not an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeOK(coll.insert({_id: "foo", a: "bar"})); - assert.writeError(coll.update({_id: "foo"}, {$set: {b: 1}}, {collation: caseInsensitive})); - assert.writeOK(coll.remove({_id: "foo"}, {justOne: true})); - } - - // Single update on string _id with collection-default collation should succeed, because it is - // an exact-ID query. +// Single update on string _id with non-collection-default collation should fail, because it is +// not an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { + assert.writeOK(coll.insert({_id: "foo", a: "bar"})); + assert.writeError(coll.update({_id: "foo"}, {$set: {b: 1}}, {collation: caseInsensitive})); + assert.writeOK(coll.remove({_id: "foo"}, {justOne: true})); +} + +// Single update on string _id with collection-default collation should succeed, because it is +// an exact-ID query. +assert.writeOK(coll.insert({_id: "foo", a: "bar"})); +writeRes = coll.update({_id: "foo"}, {$set: {b: 1}}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nMatched); +assert.writeOK(coll.remove({_id: "foo"}, {justOne: true})); + +// Single update on string _id with collection-default collation explicitly given should +// succeed, because it is an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { assert.writeOK(coll.insert({_id: "foo", a: "bar"})); - writeRes = coll.update({_id: "foo"}, {$set: {b: 1}}); + writeRes = coll.update({_id: "foo"}, {$set: {b: 1}}, {collation: {locale: "simple"}}); assert.writeOK(writeRes); assert.eq(1, writeRes.nMatched); assert.writeOK(coll.remove({_id: "foo"}, {justOne: true})); +} - // Single update on string _id with collection-default collation explicitly given should - // succeed, because it is an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeOK(coll.insert({_id: "foo", a: "bar"})); - writeRes = coll.update({_id: "foo"}, {$set: {b: 1}}, {collation: {locale: "simple"}}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nMatched); - assert.writeOK(coll.remove({_id: "foo"}, {justOne: true})); - } - - // Single update on number _id with non-collection-default collation should succeed, because it - // is an exact-ID query. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.update({_id: a_foo._id}, {$set: {b: 1}}, {collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nMatched); - } - - // Upsert must always be single-shard. - - // Upsert on strings with non-simple collation should fail, because it is not single-shard. - if (testDB.getMongo().writeMode() === "commands") { - assert.writeError(coll.update( - {a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive})); - } - - // Upsert on strings with simple collation should succeed, because it is single-shard. - writeRes = coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true}); +// Single update on number _id with non-collection-default collation should succeed, because it +// is an exact-ID query. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.update({_id: a_foo._id}, {$set: {b: 1}}, {collation: caseInsensitive}); + assert.writeOK(writeRes); + assert.eq(1, writeRes.nMatched); +} + +// Upsert must always be single-shard. + +// Upsert on strings with non-simple collation should fail, because it is not single-shard. +if (testDB.getMongo().writeMode() === "commands") { + assert.writeError(coll.update( + {a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive})); +} + +// Upsert on strings with simple collation should succeed, because it is single-shard. +writeRes = coll.update({a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true}); +assert.writeOK(writeRes); +assert.eq(1, writeRes.nMatched); +explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true}); +assert.commandWorked(explain); +assert.eq(1, explain.queryPlanner.winningPlan.shards.length); + +// Upsert on numbers with non-simple collation should succeed, because it is single shard. +if (testDB.getMongo().writeMode() === "commands") { + writeRes = coll.update( + {a: 100}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive}); assert.writeOK(writeRes); assert.eq(1, writeRes.nMatched); - explain = coll.explain().update({a: "foo"}, {$set: {b: 1}}, {multi: true, upsert: true}); + explain = coll.explain().update( + {a: 100}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive}); assert.commandWorked(explain); assert.eq(1, explain.queryPlanner.winningPlan.shards.length); +} - // Upsert on numbers with non-simple collation should succeed, because it is single shard. - if (testDB.getMongo().writeMode() === "commands") { - writeRes = coll.update( - {a: 100}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive}); - assert.writeOK(writeRes); - assert.eq(1, writeRes.nMatched); - explain = coll.explain().update( - {a: 100}, {$set: {b: 1}}, {multi: true, upsert: true, collation: caseInsensitive}); - assert.commandWorked(explain); - assert.eq(1, explain.queryPlanner.winningPlan.shards.length); - } - - st.stop(); +st.stop(); })(); |