summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-06-02 16:11:17 -0700
committerDavid Storch <david.storch@10gen.com>2016-06-03 15:54:51 -0700
commitbd5ef88fd884a2cc95eab6d4b66ce09d5efacb81 (patch)
tree3b890a9df96f32b0b870beef523ae292b199e840
parent681372e942244307067b39c5fe2b27069f5fbbe7 (diff)
downloadmongo-bd5ef88fd884a2cc95eab6d4b66ce09d5efacb81.tar.gz
SERVER-23791 harden integration testing for commands that accept a collation
Also fixes bugs in collation plumbing for the following commands: - findAndModify - group - mapReduce
-rw-r--r--jstests/core/collation_shell_helpers.js363
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp2
-rw-r--r--src/mongo/db/commands/mr.cpp1
-rw-r--r--src/mongo/db/query/get_executor.cpp1
4 files changed, 274 insertions, 93 deletions
diff --git a/jstests/core/collation_shell_helpers.js b/jstests/core/collation_shell_helpers.js
index 8c22c57512d..01755a342c8 100644
--- a/jstests/core/collation_shell_helpers.js
+++ b/jstests/core/collation_shell_helpers.js
@@ -1,16 +1,15 @@
-// Ensure that shell helpers correctly deliver the collation to the server.
-//
-// TODO SERVER-23791: Once we have an end-to-end working on mongod, we should be able to strengthen
-// the assertions in this file in order to ensure that the server is correctly respecting the
-// assertion. Currently we exercise the code paths in the shell that are supposed to propagate the
-// collation to the server, but we don't require that the result of executing the command respects
-// the collation.
+// Integration tests for the collation feature.
(function() {
'use strict';
+ load("jstests/libs/analyze_plan.js");
+
var coll = db.collation_shell_helpers;
coll.drop();
+ var explainRes;
+ var planStage;
+
var assertIndexHasCollation = function(keyPattern, collation) {
var foundIndex = false;
var indexSpecs = coll.getIndexes();
@@ -163,9 +162,45 @@
assert.commandWorked(coll.createIndexes([{e: 1}], {collation: {locale: "simple"}}));
assertIndexHasCollation({e: 1}, {locale: "simple"});
- // TODO SERVER-23791: Test that queries with matching collations can use these indices, and that
- // the indices contain collator-generated comparison keys rather than the verbatim indexed
- // strings.
+ // Test that an index with a non-simple collation contains collator-generated comparison keys
+ // rather than the verbatim indexed strings.
+ if (db.getMongo().useReadCommands()) {
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: 1}, {collation: {locale: "fr_CA"}}));
+ assert.commandWorked(coll.createIndex({b: 1}));
+ assert.writeOK(coll.insert({a: "foo", b: "foo"}));
+ assert.eq(
+ 1, coll.find({}, {_id: 0, a: 1}).collation({locale: "fr_CA"}).hint({a: 1}).itcount());
+ assert.neq(
+ "foo",
+ coll.find({}, {_id: 0, a: 1}).collation({locale: "fr_CA"}).hint({a: 1}).next().a);
+ assert.eq(
+ 1, coll.find({}, {_id: 0, b: 1}).collation({locale: "fr_CA"}).hint({b: 1}).itcount());
+ assert.eq("foo",
+ coll.find({}, {_id: 0, b: 1}).collation({locale: "fr_CA"}).hint({b: 1}).next().b);
+ }
+
+ // Test that a query with a string comparison can use an index with a non-simple collation if it
+ // has a matching collation.
+ if (db.getMongo().useReadCommands()) {
+ coll.drop();
+ assert.commandWorked(coll.createIndex({a: 1}, {collation: {locale: "fr_CA"}}));
+
+ // Query has simple collation, but index has fr_CA collation.
+ explainRes = coll.find({a: "foo"}).explain();
+ assert.commandWorked(explainRes);
+ assert(planHasStage(explainRes.queryPlanner.winningPlan, "COLLSCAN"));
+
+ // Query has en_US collation, but index has fr_CA collation.
+ explainRes = coll.find({a: "foo"}).collation({locale: "en_US"}).explain();
+ assert.commandWorked(explainRes);
+ assert(planHasStage(explainRes.queryPlanner.winningPlan, "COLLSCAN"));
+
+ // Matching collations.
+ explainRes = coll.find({a: "foo"}).collation({locale: "fr_CA"}).explain();
+ assert.commandWorked(explainRes);
+ assert(planHasStage(explainRes.queryPlanner.winningPlan, "IXSCAN"));
+ }
//
// Test helpers for operations that accept a collation.
@@ -176,7 +211,10 @@
assert.writeOK(coll.insert({_id: 2, str: "bar"}));
// Aggregation.
- assert.eq(2, coll.aggregate([], {collation: {locale: "fr"}}).itcount());
+ assert.eq(0, coll.aggregate([{$match: {str: "FOO"}}]).itcount());
+ assert.eq(1,
+ coll.aggregate([{$match: {str: "FOO"}}], {collation: {locale: "en_US", strength: 2}})
+ .itcount());
assert.commandWorked(coll.explain().aggregate([], {collation: {locale: "fr"}}));
// Count command.
@@ -186,7 +224,22 @@
assert.eq(0, coll.count({str: "FOO"}));
assert.eq(0, coll.count({str: "FOO"}, {collation: {locale: "en_US"}}));
assert.eq(1, coll.count({str: "FOO"}, {collation: {locale: "en_US", strength: 2}}));
- assert.commandWorked(coll.explain().find().collation({locale: "fr"}).count());
+
+ explainRes =
+ coll.explain("executionStats").find({str: "FOO"}).collation({locale: "en_US"}).count();
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "COLLSCAN");
+ assert.neq(null, planStage);
+ assert.eq(0, planStage.advanced);
+
+ explainRes = coll.explain("executionStats")
+ .find({str: "FOO"})
+ .collation({locale: "en_US", strength: 2})
+ .count();
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "COLLSCAN");
+ assert.neq(null, planStage);
+ assert.eq(1, planStage.advanced);
// Distinct.
assert.eq(["foo", "bar"], coll.distinct("str", {}, {collation: {locale: "fr"}}));
@@ -218,9 +271,8 @@
.itcount());
assert.commandWorked(coll.dropIndexes());
- // With a partial index.
- // {_id: 1, str: "foo"} will be indexed even though "foo" > "FOO", since the collation is
- // case-insensitive.
+ // With a partial index. {_id: 1, str: "foo"} will be indexed even though "foo" > "FOO",
+ // since the collation is case-insensitive.
assert.commandWorked(coll.ensureIndex({str: 1}, {
partialFilterExpression: {str: {$lte: "FOO"}},
collation: {locale: "en_US", strength: 2}
@@ -243,37 +295,83 @@
coll.find().collation({locale: "fr"}).itcount();
});
}
- // Explain of find always uses the find command, so this will succeed regardless of readMode.
- assert.commandWorked(coll.explain().find().collation({locale: "fr"}).finish());
- assert.commandWorked(coll.find().collation({locale: "fr"}).explain());
- // findAndModify.
- assert.eq({_id: 2, str: "baz"}, coll.findAndModify({
- query: {str: "bar"},
+ // Explain of find always uses the find command, so this will succeed regardless of readMode.
+ explainRes =
+ coll.explain("executionStats").find({str: "FOO"}).collation({locale: "en_US"}).finish();
+ assert.commandWorked(explainRes);
+ assert.eq(0, explainRes.executionStats.nReturned);
+ explainRes = coll.explain("executionStats")
+ .find({str: "FOO"})
+ .collation({locale: "en_US", strength: 2})
+ .finish();
+ assert.commandWorked(explainRes);
+ assert.eq(1, explainRes.executionStats.nReturned);
+
+ // Update via findAndModify.
+ coll.drop();
+ assert.writeOK(coll.insert({_id: 1, str: "foo"}));
+ assert.writeOK(coll.insert({_id: 2, str: "bar"}));
+ assert.eq({_id: 1, str: "baz"}, coll.findAndModify({
+ query: {str: "FOO"},
update: {$set: {str: "baz"}},
new: true,
- collation: {locale: "fr"}
+ collation: {locale: "en_US", strength: 2}
}));
- assert.commandWorked(coll.explain().findAndModify(
- {query: {str: "bar"}, update: {$set: {str: "baz"}}, new: true, collation: {locale: "fr"}}));
+ explainRes = coll.explain("executionStats").findAndModify({
+ query: {str: "BAR"},
+ update: {$set: {str: "baz"}},
+ new: true,
+ collation: {locale: "en_US", strength: 2}
+ });
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "UPDATE");
+ assert.neq(null, planStage);
+ assert.eq(1, planStage.nWouldModify);
+
+ // Delete via findAndModify.
+ coll.drop();
+ assert.writeOK(coll.insert({_id: 1, str: "foo"}));
+ assert.writeOK(coll.insert({_id: 2, str: "bar"}));
+ assert.eq({_id: 1, str: "foo"},
+ coll.findAndModify(
+ {query: {str: "FOO"}, remove: true, collation: {locale: "en_US", strength: 2}}));
+ explainRes = coll.explain("executionStats").findAndModify({
+ query: {str: "BAR"},
+ remove: true,
+ collation: {locale: "en_US", strength: 2}
+ });
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "DELETE");
+ assert.neq(null, planStage);
+ assert.eq(1, planStage.nWouldDelete);
// Group.
- assert.eq([{str: "foo", count: 1}, {str: "baz", count: 1}], coll.group({
+ coll.drop();
+ assert.writeOK(coll.insert({_id: 1, str: "foo"}));
+ assert.writeOK(coll.insert({_id: 2, str: "bar"}));
+ assert.eq([{str: "foo", count: 1}], coll.group({
+ cond: {str: "FOO"},
key: {str: 1},
initial: {count: 0},
reduce: function(curr, result) {
result.count += 1;
},
- collation: {locale: "fr"}
+ collation: {locale: "en_US", strength: 2}
}));
- assert.commandWorked(coll.explain().group({
+ explainRes = coll.explain("executionStats").group({
+ cond: {str: "FOO"},
key: {str: 1},
initial: {count: 0},
reduce: function(curr, result) {
result.count += 1;
},
- collation: {locale: "fr"}
- }));
+ collation: {locale: "en_US", strength: 2}
+ });
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "GROUP");
+ assert.neq(null, planStage);
+ assert.eq(planStage.nGroups, 1);
// mapReduce.
var mapReduceOut = coll.mapReduce(
@@ -283,24 +381,35 @@
function(key, values) {
return Array.sum(values);
},
- {out: {inline: 1}, collation: {locale: "fr"}});
+ {out: {inline: 1}, query: {str: "FOO"}, collation: {locale: "en_US", strength: 2}});
assert.commandWorked(mapReduceOut);
- assert.eq(mapReduceOut.results.length, 2);
+ assert.eq(mapReduceOut.results.length, 1);
// Remove.
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- assert.commandWorked(
- coll.explain().remove({str: "foo"}, {justOne: true, collation: {locale: "fr"}}));
- assert.writeOK(coll.remove({str: "foo"}, {justOne: true, collation: {locale: "fr"}}));
+ explainRes = coll.explain("executionStats").remove({str: "FOO"}, {
+ justOne: true,
+ collation: {locale: "en_US", strength: 2}
+ });
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "DELETE");
+ assert.neq(null, planStage);
+ assert.eq(1, planStage.nWouldDelete);
+
+ var writeRes =
+ coll.remove({str: "FOO"}, {justOne: true, collation: {locale: "en_US", strength: 2}});
+ assert.writeOK(writeRes);
+ assert.eq(1, writeRes.nRemoved);
} else {
assert.throws(function() {
- coll.remove({str: "foo"}, {justOne: true, collation: {locale: "fr"}});
+ coll.remove({str: "FOO"}, {justOne: true, collation: {locale: "en_US", strength: 2}});
});
assert.throws(function() {
- coll.explain().remove({str: "foo"}, {justOne: true, collation: {locale: "fr"}});
+ coll.explain().remove({str: "FOO"},
+ {justOne: true, collation: {locale: "en_US", strength: 2}});
});
}
@@ -309,18 +418,29 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- assert.commandWorked(coll.explain().update(
- {str: "foo"}, {$set: {other: 99}}, {multi: true, collation: {locale: "fr"}}));
- assert.writeOK(coll.update(
- {str: "foo"}, {$set: {other: 99}}, {multi: true, collation: {locale: "fr"}}));
+ explainRes = coll.explain("executionStats").update({str: "FOO"}, {$set: {other: 99}}, {
+ multi: true,
+ collation: {locale: "en_US", strength: 2}
+ });
+ assert.commandWorked(explainRes);
+ planStage = getPlanStage(explainRes.executionStats.executionStages, "UPDATE");
+ assert.neq(null, planStage);
+ assert.eq(2, planStage.nWouldModify);
+
+ var writeRes = coll.update({str: "FOO"},
+ {$set: {other: 99}},
+ {multi: true, collation: {locale: "en_US", strength: 2}});
+ assert.eq(2, writeRes.nModified);
} else {
assert.throws(function() {
- coll.update(
- {str: "foo"}, {$set: {other: 99}}, {multi: true, collation: {locale: "fr"}});
+ coll.update({str: "FOO"},
+ {$set: {other: 99}},
+ {multi: true, collation: {locale: "en_US", strength: 2}});
});
assert.throws(function() {
- coll.explain().update(
- {str: "foo"}, {$set: {other: 99}}, {multi: true, collation: {locale: "fr"}});
+ coll.explain().update({str: "FOO"},
+ {$set: {other: 99}},
+ {multi: true, collation: {locale: "en_US", strength: 2}});
});
}
@@ -506,62 +626,96 @@
var bulk;
if (db.getMongo().writeMode() !== "commands") {
+ coll.drop();
+ assert.writeOK(coll.insert({_id: 1, str: "foo"}));
+ assert.writeOK(coll.insert({_id: 2, str: "foo"}));
+
// Can't use the bulk API to set a collation when using legacy write ops.
bulk = coll.initializeUnorderedBulkOp();
assert.throws(function() {
- bulk.find({str: "foo"}).collation({locale: "fr"});
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2});
});
bulk = coll.initializeOrderedBulkOp();
assert.throws(function() {
- bulk.find({str: "foo"}).collation({locale: "en_US"});
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2});
});
} else {
+ var writeRes;
+
// update().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).update({$set: {other: 99}});
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).update({
+ $set: {other: 99}
+ });
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(2, writeRes.nModified);
// updateOne().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).updateOne({$set: {other: 99}});
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).updateOne({
+ $set: {other: 99}
+ });
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(1, writeRes.nModified);
// replaceOne().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).replaceOne({str: "oof"});
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).replaceOne({str: "oof"});
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(1, writeRes.nModified);
// replaceOne() with upsert().
coll.drop();
+ assert.writeOK(coll.insert({_id: 1, str: "foo"}));
+ assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).upsert().replaceOne({str: "foo"});
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US"}).upsert().replaceOne({str: "foo"});
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(1, writeRes.nUpserted);
+ assert.eq(0, writeRes.nModified);
+
+ bulk = coll.initializeUnorderedBulkOp();
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).upsert().replaceOne({
+ str: "foo"
+ });
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(0, writeRes.nUpserted);
+ assert.eq(1, writeRes.nModified);
// removeOne().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).removeOne();
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).removeOne();
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(1, writeRes.nRemoved);
// remove().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
bulk = coll.initializeUnorderedBulkOp();
- bulk.find({str: "foo"}).collation({locale: "fr"}).remove();
- assert.writeOK(bulk.execute());
+ bulk.find({str: "FOO"}).collation({locale: "en_US", strength: 2}).remove();
+ writeRes = bulk.execute();
+ assert.writeOK(writeRes);
+ assert.eq(2, writeRes.nRemoved);
}
//
@@ -573,11 +727,11 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.deleteOne({str: "foo"}, {collation: {locale: "fr"}});
+ var res = coll.deleteOne({str: "FOO"}, {collation: {locale: "en_US", strength: 2}});
assert.eq(1, res.deletedCount);
} else {
assert.throws(function() {
- coll.deleteOne({str: "foo"}, {collation: {locale: "fr"}});
+ coll.deleteOne({str: "FOO"}, {collation: {locale: "en_US", strength: 2}});
});
}
@@ -586,11 +740,11 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.deleteMany({str: "foo"}, {collation: {locale: "fr"}});
+ var res = coll.deleteMany({str: "FOO"}, {collation: {locale: "en_US", strength: 2}});
assert.eq(2, res.deletedCount);
} else {
assert.throws(function() {
- coll.deleteMany({str: "foo"}, {collation: {locale: "fr"}});
+ coll.deleteMany({str: "FOO"}, {collation: {locale: "en_US", strength: 2}});
});
}
@@ -598,22 +752,23 @@
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.eq({_id: 1, str: "foo"},
- coll.findOneAndDelete({str: "foo"}, {collation: {locale: "fr"}}));
+ coll.findOneAndDelete({str: "FOO"}, {collation: {locale: "en_US", strength: 2}}));
assert.eq(null, coll.findOne({_id: 1}));
// findOneAndReplace().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.eq({_id: 1, str: "foo"},
- coll.findOneAndReplace({str: "foo"}, {str: "bar"}, {collation: {locale: "fr"}}));
+ coll.findOneAndReplace(
+ {str: "FOO"}, {str: "bar"}, {collation: {locale: "en_US", strength: 2}}));
assert.neq(null, coll.findOne({str: "bar"}));
// findOneAndUpdate().
coll.drop();
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
- assert.eq(
- {_id: 1, str: "foo"},
- coll.findOneAndUpdate({str: "foo"}, {$set: {other: 99}}, {collation: {locale: "fr"}}));
+ assert.eq({_id: 1, str: "foo"},
+ coll.findOneAndUpdate(
+ {str: "FOO"}, {$set: {other: 99}}, {collation: {locale: "en_US", strength: 2}}));
assert.neq(null, coll.findOne({other: 99}));
// replaceOne().
@@ -621,11 +776,13 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.replaceOne({str: "foo"}, {str: "bar"}, {collation: {locale: "fr"}});
+ var res = coll.replaceOne(
+ {str: "FOO"}, {str: "bar"}, {collation: {locale: "en_US", strength: 2}});
assert.eq(1, res.modifiedCount);
} else {
assert.throws(function() {
- coll.replaceOne({str: "foo"}, {str: "bar"}, {collation: {locale: "fr"}});
+ coll.replaceOne(
+ {str: "FOO"}, {str: "bar"}, {collation: {locale: "en_US", strength: 2}});
});
}
@@ -634,11 +791,13 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.updateOne({str: "foo"}, {$set: {other: 99}}, {collation: {locale: "fr"}});
+ var res = coll.updateOne(
+ {str: "FOO"}, {$set: {other: 99}}, {collation: {locale: "en_US", strength: 2}});
assert.eq(1, res.modifiedCount);
} else {
assert.throws(function() {
- coll.updateOne({str: "foo"}, {$set: {other: 99}}, {collation: {locale: "fr"}});
+ coll.updateOne(
+ {str: "FOO"}, {$set: {other: 99}}, {collation: {locale: "en_US", strength: 2}});
});
}
@@ -647,11 +806,13 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.updateMany({str: "foo"}, {$set: {other: 99}}, {collation: {locale: "fr"}});
+ var res = coll.updateMany(
+ {str: "FOO"}, {$set: {other: 99}}, {collation: {locale: "en_US", strength: 2}});
assert.eq(2, res.modifiedCount);
} else {
assert.throws(function() {
- coll.updateMany({str: "foo"}, {$set: {other: 99}}, {collation: {locale: "fr"}});
+ coll.updateMany(
+ {str: "FOO"}, {$set: {other: 99}}, {collation: {locale: "en_US", strength: 2}});
});
}
@@ -661,17 +822,20 @@
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
var res = coll.bulkWrite([{
- updateOne:
- {filter: {str: "foo"}, update: {$set: {other: 99}}, collation: {locale: "fr"}}
+ updateOne: {
+ filter: {str: "FOO"},
+ update: {$set: {other: 99}},
+ collation: {locale: "en_US", strength: 2}
+ }
}]);
assert.eq(1, res.matchedCount);
} else {
assert.throws(function() {
coll.bulkWrite([{
updateOne: {
- filter: {str: "foo"},
+ filter: {str: "FOO"},
update: {$set: {other: 99}},
- collation: {locale: "fr"}
+ collation: {locale: "en_US", strength: 2}
}
}]);
});
@@ -683,17 +847,20 @@
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
var res = coll.bulkWrite([{
- updateMany:
- {filter: {str: "foo"}, update: {$set: {other: 99}}, collation: {locale: "fr"}}
+ updateMany: {
+ filter: {str: "FOO"},
+ update: {$set: {other: 99}},
+ collation: {locale: "en_US", strength: 2}
+ }
}]);
assert.eq(2, res.matchedCount);
} else {
assert.throws(function() {
coll.bulkWrite([{
updateMany: {
- filter: {str: "foo"},
+ filter: {str: "FOO"},
update: {$set: {other: 99}},
- collation: {locale: "fr"}
+ collation: {locale: "en_US", strength: 2}
}
}]);
});
@@ -705,15 +872,21 @@
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
var res = coll.bulkWrite([{
- replaceOne:
- {filter: {str: "foo"}, replacement: {str: "bar"}, collation: {locale: "fr"}}
+ replaceOne: {
+ filter: {str: "FOO"},
+ replacement: {str: "bar"},
+ collation: {locale: "en_US", strength: 2}
+ }
}]);
assert.eq(1, res.matchedCount);
} else {
assert.throws(function() {
coll.bulkWrite([{
- replaceOne:
- {filter: {str: "foo"}, replacement: {str: "bar"}, collation: {locale: "fr"}}
+ replaceOne: {
+ filter: {str: "FOO"},
+ replacement: {str: "bar"},
+ collation: {locale: "en_US", strength: 2}
+ }
}]);
});
}
@@ -723,11 +896,13 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.bulkWrite([{deleteOne: {filter: {str: "foo"}, collation: {locale: "fr"}}}]);
+ var res = coll.bulkWrite(
+ [{deleteOne: {filter: {str: "FOO"}, collation: {locale: "en_US", strength: 2}}}]);
assert.eq(1, res.deletedCount);
} else {
assert.throws(function() {
- coll.bulkWrite([{deleteOne: {filter: {str: "foo"}, collation: {locale: "fr"}}}]);
+ coll.bulkWrite(
+ [{deleteOne: {filter: {str: "FOO"}, collation: {locale: "en_US", strength: 2}}}]);
});
}
@@ -736,11 +911,13 @@
assert.writeOK(coll.insert({_id: 1, str: "foo"}));
assert.writeOK(coll.insert({_id: 2, str: "foo"}));
if (db.getMongo().writeMode() === "commands") {
- var res = coll.bulkWrite([{deleteMany: {filter: {str: "foo"}, collation: {locale: "fr"}}}]);
+ var res = coll.bulkWrite(
+ [{deleteMany: {filter: {str: "FOO"}, collation: {locale: "en_US", strength: 2}}}]);
assert.eq(2, res.deletedCount);
} else {
assert.throws(function() {
- coll.bulkWrite([{deleteMany: {filter: {str: "foo"}, collation: {locale: "fr"}}}]);
+ coll.bulkWrite(
+ [{deleteMany: {filter: {str: "FOO"}, collation: {locale: "en_US", strength: 2}}}]);
});
}
@@ -750,15 +927,15 @@
assert.writeOK(coll.insert({_id: 2, str: "bar"}));
if (db.getMongo().writeMode() === "commands") {
var res = coll.bulkWrite([
- {deleteOne: {filter: {str: "foo"}, collation: {locale: "fr"}}},
- {deleteOne: {filter: {str: "bar"}, collation: {locale: "en_US"}}}
+ {deleteOne: {filter: {str: "FOO"}, collation: {locale: "fr", strength: 2}}},
+ {deleteOne: {filter: {str: "BAR"}, collation: {locale: "en_US", strength: 2}}}
]);
assert.eq(2, res.deletedCount);
} else {
assert.throws(function() {
coll.bulkWrite([
- {deleteOne: {filter: {str: "foo"}, collation: {locale: "fr"}}},
- {deleteOne: {filter: {str: "bar"}, collation: {locale: "en_US"}}}
+ {deleteOne: {filter: {str: "FOO"}, collation: {locale: "fr", strength: 2}}},
+ {deleteOne: {filter: {str: "BAR"}, collation: {locale: "en_US", strength: 2}}}
]);
});
}
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index dd1e04f311b..6efdb157ad8 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -143,6 +143,7 @@ void makeUpdateRequest(const FindAndModifyRequest& args,
requestOut->setProj(args.getFields());
requestOut->setUpdates(args.getUpdateObj());
requestOut->setSort(args.getSort());
+ requestOut->setCollation(args.getCollation());
requestOut->setUpsert(args.isUpsert());
requestOut->setReturnDocs(args.shouldReturnNew() ? UpdateRequest::RETURN_NEW
: UpdateRequest::RETURN_OLD);
@@ -156,6 +157,7 @@ void makeDeleteRequest(const FindAndModifyRequest& args, bool explain, DeleteReq
requestOut->setQuery(args.getQuery());
requestOut->setProj(args.getFields());
requestOut->setSort(args.getSort());
+ requestOut->setCollation(args.getCollation());
requestOut->setMulti(false);
requestOut->setYieldPolicy(PlanExecutor::YIELD_AUTO);
requestOut->setReturnDeleted(true); // Always return the old value.
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index b86382a7903..14acf44d7f3 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -1447,6 +1447,7 @@ public:
auto qr = stdx::make_unique<QueryRequest>(nss);
qr->setFilter(config.filter);
qr->setSort(config.sort);
+ qr->setCollation(config.collation);
const ExtensionsCallbackReal extensionsCallback(txn, &nss);
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 22efcb696de..2b05871af47 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -942,6 +942,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorGroup(OperationContext* txn,
const NamespaceString nss(request.ns);
auto qr = stdx::make_unique<QueryRequest>(nss);
qr->setFilter(request.query);
+ qr->setCollation(request.collation);
qr->setExplain(request.explain);
const ExtensionsCallbackReal extensionsCallback(txn, &nss);