summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/graphLookup/collation_graphlookup.js
blob: f3fbcf2ee345e450edf5b93ebb438abba7dd27e3 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Cannot implicitly shard accessed collections because unsupported use of sharded collection
// for target collection of $lookup and $graphLookup.
// @tags: [assumes_unsharded_collection]

/**
 * Tests that the $graphLookup stage respects the collation when matching between the
 * 'connectFromField' and the 'connectToField'.  $graphLookup should use the collation
 * set on the aggregation, or the default collation of the collection.
 */
(function() {
"use strict";

var res;
const caseInsensitiveUS = {
    collation: {locale: "en_US", strength: 2}
};
const caseSensitiveUS = {
    collation: {locale: "en_US", strength: 3}
};

var coll = db.collation_graphlookup;
var foreignColl = db.collation_graphlookup_foreign;

// Test that $graphLookup respects the collation set on the aggregation pipeline. Case
// insensitivity should mean that we find both "jeremy" and "jimmy" as friends.
coll.drop();
assert.writeOK(coll.insert({username: "erica", friends: ["jeremy", "jimmy"]}));
assert.writeOK(coll.insert([{username: "JEREMY"}, {username: "JIMMY"}]));

res = coll.aggregate(
                  [
                    {$match: {username: "erica"}},
                    {
                      $graphLookup: {
                          from: coll.getName(),
                          startWith: "$friends",
                          connectFromField: "friends",
                          connectToField: "username",
                          as: "friendUsers"
                      }
                    }
                  ],
                  caseInsensitiveUS)
              .toArray();
assert.eq(1, res.length);
assert.eq("erica", res[0].username);
assert.eq(2, res[0].friendUsers.length);

// Negative test: ensure that we don't find any friends when the collation is simple.
res = coll.aggregate([
                  {$match: {username: "erica"}},
                  {
                    $graphLookup: {
                        from: coll.getName(),
                        startWith: "$friends",
                        connectFromField: "friends",
                        connectToField: "username",
                        as: "friendUsers"
                    }
                  }
              ])
              .toArray();
assert.eq(1, res.length);
assert.eq("erica", res[0].username);
assert.eq(0, res[0].friendUsers.length);

coll.drop();
assert.commandWorked(db.createCollection(coll.getName(), caseInsensitiveUS));
assert.writeOK(coll.insert({username: "erica", friends: ["jeremy", "jimmy"]}));
foreignColl.drop();
assert.commandWorked(db.createCollection(foreignColl.getName(), caseSensitiveUS));
assert.writeOK(foreignColl.insert([{username: "JEREMY"}, {username: "JIMMY"}]));

// Test that $graphLookup inherits the default collation of the collection on which it is run,
// and that this collation is used instead of the default collation of the foreign collection.
res = coll.aggregate([
                  {$match: {username: "erica"}},
                  {
                    $graphLookup: {
                        from: foreignColl.getName(),
                        startWith: "$friends",
                        connectFromField: "friends",
                        connectToField: "username",
                        as: "friendUsers"
                    }
                  }
              ])
              .toArray();
assert.eq(1, res.length);
assert.eq("erica", res[0].username);
assert.eq(2, res[0].friendUsers.length);

// Test that we don't use the collation to dedup string _id values. This would cause us to miss
// nodes in the graph that have distinct _id values which compare equal under the collation.
coll.drop();
assert.writeOK(coll.insert({username: "erica", friends: ["jeremy"]}));
assert.writeOK(coll.insert({_id: "foo", username: "JEREMY", friends: ["jimmy"]}));
assert.writeOK(coll.insert({_id: "FOO", username: "jimmy", friends: []}));

res = coll.aggregate(
                  [
                    {$match: {username: "erica"}},
                    {
                      $graphLookup: {
                          from: coll.getName(),
                          startWith: "$friends",
                          connectFromField: "friends",
                          connectToField: "username",
                          as: "friendUsers"
                      }
                    }
                  ],
                  caseInsensitiveUS)
              .toArray();
assert.eq(1, res.length);
assert.eq("erica", res[0].username);
assert.eq(2, res[0].friendUsers.length);

// Test that the result set is not deduplicated under the collation. If two documents are
// entirely equal under the collation, they should still both get returned in the "as" field.
coll.drop();
assert.writeOK(coll.insert({username: "erica", friends: ["jeremy"]}));
assert.writeOK(coll.insert({_id: "foo", username: "jeremy"}));
assert.writeOK(coll.insert({_id: "FOO", username: "JEREMY"}));

res = coll.aggregate(
                  [
                    {$match: {username: "erica"}},
                    {
                      $graphLookup: {
                          from: coll.getName(),
                          startWith: "$friends",
                          connectFromField: "friends",
                          connectToField: "username",
                          as: "friendUsers"
                      }
                    }
                  ],
                  caseInsensitiveUS)
              .toArray();
assert.eq(1, res.length);
assert.eq("erica", res[0].username);
assert.eq(2, res[0].friendUsers.length);
})();