summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/lookup/lookup_collation.js
blob: 13bacca992ce408bd9d7699ee0064503dc047f15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
 * Tests that $lookup respects the user-specified collation or the inherited local collation
 * when performing comparisons on a foreign collection with a different default collation. Exercises
 * the fix for SERVER-43350.
 */
load("jstests/aggregation/extras/utils.js");  // For anyEq.
load("jstests/libs/sbe_util.js");             // For checkSBEEnabled.

(function() {

"use strict";

load("jstests/libs/fixture_helpers.js");  // For isSharded.

const testDB = db.getSiblingDB(jsTestName());
assert.commandWorked(testDB.dropDatabase());

// TODO SERVER-64482 Reenable this test when SERVER-64482 is done.
if (checkSBEEnabled(testDB, ["featureFlagSBELookupPushdown"])) {
    jsTestLog("Skipping test because SBE and SBE $lookup features are both enabled.");
    return;
}

const caseInsensitiveCollation = {
    locale: "en_US",
    strength: 1
};

const simpleCollation = {
    locale: "simple"
};

assert.commandWorked(testDB.createCollection("no_collation"));
assert.commandWorked(
    testDB.createCollection("case_insensitive", {collation: caseInsensitiveCollation}));

const noCollationColl = testDB.no_collation;
const caseInsensitiveColl = testDB.case_insensitive;

// Do not run the rest of the tests if the foreign collection is implicitly sharded but the flag to
// allow $lookup/$graphLookup into a sharded collection is disabled.
const getShardedLookupParam = db.adminCommand({getParameter: 1, featureFlagShardedLookup: 1});
const isShardedLookupEnabled = getShardedLookupParam.hasOwnProperty("featureFlagShardedLookup") &&
    getShardedLookupParam.featureFlagShardedLookup.value;
if (FixtureHelpers.isSharded(caseInsensitiveColl) && !isShardedLookupEnabled) {
    return;
}

assert.commandWorked(
    noCollationColl.insert([{_id: "a"}, {_id: "b"}, {_id: "c"}, {_id: "d"}, {_id: "e"}]));
assert.commandWorked(
    caseInsensitiveColl.insert([{_id: "a"}, {_id: "B"}, {_id: "c"}, {_id: "D"}, {_id: "e"}]));

const lookupWithPipeline = (foreignColl) => {
    return {
        $lookup: {from: foreignColl.getName(), as: "foreignMatch", let: {l_id: "$_id"}, pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}]}
    };
};
const lookupNoPipeline = (foreignColl) => {
    return {
        $lookup: {from: foreignColl.getName(), localField: "_id", foreignField: "_id", as: "foreignMatch"}
    };
};

for (let lookupInto of [lookupWithPipeline, lookupNoPipeline]) {
    // Verify that a $lookup whose local collection has no default collation uses the simple
    // collation for comparisons on a foreign collection with a non-simple default collation.
    let results = noCollationColl.aggregate([lookupInto(caseInsensitiveColl)]).toArray();
    assert(anyEq(results, [
        {_id: "a", foreignMatch: [{_id: "a"}]},
        {_id: "b", foreignMatch: []},
        {_id: "c", foreignMatch: [{_id: "c"}]},
        {_id: "d", foreignMatch: []},
        {_id: "e", foreignMatch: [{_id: "e"}]}
    ]));

    // Verify that a $lookup whose local collection has no default collation but which is running in
    // a pipeline with a non-simple user-specified collation uses the latter for comparisons on the
    // foreign collection.
    results =
        noCollationColl
            .aggregate([lookupInto(caseInsensitiveColl)], {collation: caseInsensitiveCollation})
            .toArray();
    assert(anyEq(results, [
        {_id: "a", foreignMatch: [{_id: "a"}]},
        {_id: "b", foreignMatch: [{_id: "B"}]},
        {_id: "c", foreignMatch: [{_id: "c"}]},
        {_id: "d", foreignMatch: [{_id: "D"}]},
        {_id: "e", foreignMatch: [{_id: "e"}]}
    ]));

    // Verify that a $lookup whose local collection has a non-simple collation uses the latter for
    // comparisons on a foreign collection with no default collation.
    results = caseInsensitiveColl.aggregate([lookupInto(noCollationColl)]).toArray();
    assert(anyEq(results, [
        {_id: "a", foreignMatch: [{_id: "a"}]},
        {_id: "B", foreignMatch: [{_id: "b"}]},
        {_id: "c", foreignMatch: [{_id: "c"}]},
        {_id: "D", foreignMatch: [{_id: "d"}]},
        {_id: "e", foreignMatch: [{_id: "e"}]}
    ]));

    // Verify that a $lookup whose local collection has a non-simple collation but which is running
    // in a pipeline with a user-specified simple collation uses the latter for comparisons on the
    // foreign collection.
    results =
        caseInsensitiveColl.aggregate([lookupInto(noCollationColl)], {collation: simpleCollation})
            .toArray();
    assert(anyEq(results, [
        {_id: "a", foreignMatch: [{_id: "a"}]},
        {_id: "B", foreignMatch: []},
        {_id: "c", foreignMatch: [{_id: "c"}]},
        {_id: "D", foreignMatch: []},
        {_id: "e", foreignMatch: [{_id: "e"}]}
    ]));
}
})();