mirror of https://github.com/mongodb/mongo
336 lines
9.9 KiB
JavaScript
336 lines
9.9 KiB
JavaScript
// Cannot implicitly shard accessed collections because of collection existing when none expected.
|
|
// @tags: [
|
|
// assumes_no_implicit_collection_creation_after_drop,
|
|
// ]
|
|
|
|
// Test that expressions which make can make string comparisons respect the collation.
|
|
import {testExpression, testExpressionWithCollation} from "jstests/aggregation/extras/utils.js";
|
|
|
|
let coll = db.collation_expressions;
|
|
coll.drop();
|
|
|
|
let results;
|
|
const caseInsensitive = {
|
|
locale: "en_US",
|
|
strength: 2,
|
|
};
|
|
const numericOrdering = {
|
|
locale: "en_US",
|
|
numericOrdering: true,
|
|
};
|
|
|
|
// Test that $cmp respects the collection-default collation.
|
|
assert.commandWorked(db.createCollection(coll.getName(), {collation: caseInsensitive}));
|
|
testExpression(coll, {$cmp: ["a", "A"]}, 0);
|
|
|
|
coll.drop();
|
|
|
|
// Test that $cmp respects the collation.
|
|
testExpressionWithCollation(coll, {$cmp: ["a", "A"]}, 0, caseInsensitive);
|
|
|
|
// Test that $eq respects the collation.
|
|
testExpressionWithCollation(coll, {$eq: ["a", "A"]}, true, caseInsensitive);
|
|
|
|
// Test that $ne respects the collation.
|
|
testExpressionWithCollation(coll, {$ne: ["a", "A"]}, false, caseInsensitive);
|
|
|
|
// Test that $lt respects the collation.
|
|
testExpressionWithCollation(coll, {$lt: ["2", "10"]}, true, numericOrdering);
|
|
|
|
// Test that $lte respects the collation.
|
|
testExpressionWithCollation(coll, {$lte: ["2", "10"]}, true, numericOrdering);
|
|
testExpressionWithCollation(coll, {$lte: ["b", "B"]}, true, caseInsensitive);
|
|
|
|
// Test that $gt respects the collation.
|
|
testExpressionWithCollation(coll, {$gt: ["2", "10"]}, false, numericOrdering);
|
|
|
|
// Test that $gte respects the collation.
|
|
testExpressionWithCollation(coll, {$gte: ["2", "10"]}, false, numericOrdering);
|
|
testExpressionWithCollation(coll, {$gte: ["b", "B"]}, true, caseInsensitive);
|
|
|
|
// Test that $in respects the collation.
|
|
testExpressionWithCollation(coll, {$in: ["A", [1, 2, "a", 3, 4]]}, true, caseInsensitive);
|
|
|
|
// Test that $indexOfArray respects the collation.
|
|
testExpressionWithCollation(coll, {$indexOfArray: [[1, 2, "a", "b", "c", "B"], "B"]}, 3, caseInsensitive);
|
|
|
|
// Test that $indexOfBytes doesn't respect the collation.
|
|
testExpressionWithCollation(coll, {$indexOfBytes: ["12abcB", "B"]}, 5, caseInsensitive);
|
|
|
|
// Test that $indexOfCP doesn't respect the collation.
|
|
testExpressionWithCollation(coll, {$indexOfCP: ["12abcB", "B"]}, 5, caseInsensitive);
|
|
|
|
// Test that $strcasecmp doesn't respect the collation.
|
|
testExpressionWithCollation(coll, {$strcasecmp: ["100", "2"]}, -1, numericOrdering);
|
|
|
|
// Test that $setEquals respects the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$setEquals: [
|
|
["a", "B"],
|
|
["b", "A"],
|
|
],
|
|
},
|
|
true,
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $setIntersection respects the collation.
|
|
results = coll
|
|
.aggregate(
|
|
[
|
|
{
|
|
$project: {
|
|
out: {
|
|
$setIntersection: [
|
|
["a", "B", "c"],
|
|
["d", "b", "A"],
|
|
],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
{collation: caseInsensitive},
|
|
)
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(2, results[0].out.length);
|
|
|
|
// Test that $setUnion respects the collation.
|
|
results = coll
|
|
.aggregate(
|
|
[
|
|
{
|
|
$project: {
|
|
out: {
|
|
$setUnion: [
|
|
["a", "B", "c"],
|
|
["d", "b", "A"],
|
|
],
|
|
},
|
|
},
|
|
},
|
|
],
|
|
{collation: caseInsensitive},
|
|
)
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(4, results[0].out.length);
|
|
|
|
// Test that $setUnion is not commutative when a collation is set. A non-const value is required for
|
|
// reordering to occur.
|
|
assert(coll.drop);
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, upper: "A", lower: "a"}));
|
|
let results1 = coll
|
|
.aggregate([{$project: {out: {$setUnion: [["$upper"], ["a"]]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
let results2 = coll
|
|
.aggregate([{$project: {out: {$setUnion: [["A"], ["$lower"]]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(results1, results2);
|
|
|
|
// Test that $setDifference respects the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$setDifference: [
|
|
["a", "B"],
|
|
["b", "A"],
|
|
],
|
|
},
|
|
[],
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $setIsSubset respects the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$setIsSubset: [
|
|
["a", "B"],
|
|
["b", "A", "c"],
|
|
],
|
|
},
|
|
true,
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $split doesn't respect the collation.
|
|
testExpressionWithCollation(coll, {$split: ["abc", "B"]}, ["abc"], caseInsensitive);
|
|
|
|
// Test that an $and which can be optimized out respects the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, str: "A"}));
|
|
results = coll
|
|
.aggregate([{$project: {out: {$and: [{$eq: ["$str", "a"]}, {$eq: ["b", "B"]}]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(true, results[0].out);
|
|
|
|
// Test that an $and which cannot be optimized out respects the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, str: "A", str2: "B"}));
|
|
results = coll
|
|
.aggregate([{$project: {out: {$and: [{$eq: ["$str", "a"]}, {$eq: ["$str2", "b"]}]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(true, results[0].out);
|
|
|
|
// Test that an $or which can be optimized out respects the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, str: "A"}));
|
|
results = coll
|
|
.aggregate([{$project: {out: {$or: [{$eq: ["$str", "a"]}, {$eq: ["b", "c"]}]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(true, results[0].out);
|
|
|
|
// Test that an $or which cannot be optimized out respects the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, str: "A", str2: "B"}));
|
|
results = coll
|
|
.aggregate([{$project: {out: {$or: [{$eq: ["$str", "c"]}, {$eq: ["$str2", "b"]}]}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(true, results[0].out);
|
|
|
|
// Test that $filter's subexpressions respect the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$filter: {
|
|
input: {
|
|
$cond: {
|
|
if: {$eq: ["FOO", "foo"]},
|
|
then: ["a", "b", "A", "c", "C", "d"],
|
|
else: null,
|
|
},
|
|
},
|
|
as: "str",
|
|
cond: {$or: [{$eq: ["$$str", "a"]}, {$eq: ["$$str", "c"]}]},
|
|
},
|
|
},
|
|
["a", "A", "c", "C"],
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $let's subexpressions respect the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$let: {
|
|
vars: {str: {$cond: [{$eq: ["A", "a"]}, "b", "c"]}},
|
|
in: {$cond: [{$eq: ["$$str", "B"]}, "d", "e"]},
|
|
},
|
|
},
|
|
"d",
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $map's subexpressions respect the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$map: {
|
|
input: {$cond: [{$eq: ["A", "a"]}, ["aa", "a", "AA", "b"], null]},
|
|
as: "val",
|
|
in: {$and: [{$eq: ["$$val", "aA"]}, {$eq: ["$$val", "Aa"]}]},
|
|
},
|
|
},
|
|
[true, false, true, false],
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $group stage's _id expressions respect the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1}));
|
|
results = coll
|
|
.aggregate([{$group: {_id: {a: {$eq: ["a", "A"]}, b: {$eq: ["b", "B"]}}}}], {collation: caseInsensitive})
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(true, results[0]._id.a);
|
|
assert.eq(true, results[0]._id.b);
|
|
|
|
// Test that $reduce's subexpressions respect the collation.
|
|
testExpressionWithCollation(
|
|
coll,
|
|
{
|
|
$reduce: {
|
|
input: {$cond: [{$eq: ["a", "A"]}, [1, 2, 3], null]},
|
|
initialValue: {$cond: [{$eq: ["a", "A"]}, {sum: 1}, {sum: 0}]},
|
|
in: {
|
|
$cond: [{$eq: ["a", "A"]}, {sum: {$add: ["$$value.sum", "$$this"]}}, {sum: 0}],
|
|
},
|
|
},
|
|
},
|
|
{sum: 7},
|
|
caseInsensitive,
|
|
);
|
|
|
|
// Test that $switch's subexpressions respect the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 1, a: "A"}));
|
|
assert.commandWorked(coll.insert({_id: 2, b: "B"}));
|
|
assert.commandWorked(coll.insert({_id: 3, c: "C"}));
|
|
results = coll
|
|
.aggregate(
|
|
[
|
|
{$sort: {_id: 1}},
|
|
{
|
|
$project: {
|
|
out: {
|
|
$switch: {
|
|
branches: [
|
|
{case: {$eq: ["$a", "a"]}, then: "foo"},
|
|
{case: {$eq: ["$b", "b"]}, then: "bar"},
|
|
],
|
|
default: "baz",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
{collation: caseInsensitive},
|
|
)
|
|
.toArray();
|
|
assert.eq(3, results.length);
|
|
assert.eq("foo", results[0].out);
|
|
assert.eq("bar", results[1].out);
|
|
assert.eq("baz", results[2].out);
|
|
|
|
// Test that a $zip's subexpressions respect the collation.
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 0, evens: [0, 2, 4], odds: [1, 3]}));
|
|
results = coll
|
|
.aggregate(
|
|
[
|
|
{
|
|
$project: {
|
|
out: {
|
|
$zip: {
|
|
inputs: [
|
|
{$cond: [{$eq: ["A", "a"]}, "$evens", "$odds"]},
|
|
{$cond: [{$eq: ["B", "b"]}, "$odds", "$evens"]},
|
|
],
|
|
defaults: [0, {$cond: [{$eq: ["C", "c"]}, 5, 7]}],
|
|
useLongestLength: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
{collation: caseInsensitive},
|
|
)
|
|
.toArray();
|
|
assert.eq(1, results.length);
|
|
assert.eq(
|
|
[
|
|
[0, 1],
|
|
[2, 3],
|
|
[4, 5],
|
|
],
|
|
results[0].out,
|
|
);
|