summaryrefslogtreecommitdiff
path: root/jstests/core/index_multiple_compatibility.js
blob: 5a2a599f536be0b204ed86a593bc8dcfc238965d (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Cannot implicitly shard accessed collections because of not being able to create unique index
// using hashed shard key pattern.
// @tags: [cannot_create_unique_index_when_using_hashed_shard_key, requires_non_retryable_writes]

// Test that multiple indexes behave correctly together.
(function() {
'use strict';
var coll = db.index_multiple_compatibility;
coll.drop();

const enUSStrength1 = {
    locale: "en_US",
    strength: 1
};
const enUSStrength2 = {
    locale: "en_US",
    strength: 2
};
const enUSStrength3 = {
    locale: "en_US",
    strength: 3
};

/**
 * testIndexCompat runs a series of operations on two indexes to ensure that the two behave
 * properly in combination.
 *
 * 'index1' and 'index2' take a document in the following format:
 *
 * {
 *     index: {key: Document, name: String, collation: Document, options...}
 *     doc: Document
 * }
 *
 * The 'index' key indicates the index to create, and 'doc' (optional) indicates a document to
 * insert in the collection, and look for in *only* this index.  The 'index' key will be passed
 * directly to the createIndexes command.
 *
 * 'both' optionally provides a document to insert into the collection, and expect in both
 * indexes.
 *
 * - Create both indexes.
 * - Insert document in index1.
 * - Check that it is present in index1, and absent in index2, using find and a hint.
 * - Insert document in index2.
 * - Check that it is present in index2, and absent in index1, using find and a hint.
 * - Insert the document 'both', if it is provided.  Check that it is inserted in both indexes.
 * - Delete documents ensuring they are removed from the appropriate indexes.
 */
function testIndexCompat(coll, index1, index2, both) {
    coll.drop();

    assert(index1.hasOwnProperty('index'));
    assert(index2.hasOwnProperty('index'));

    assert.commandWorked(
        db.runCommand({createIndexes: coll.getName(), indexes: [index1.index, index2.index]}));

    // Check index 1 document.
    if (index1.hasOwnProperty('doc')) {
        assert.commandWorked(coll.insert(index1.doc));
        assert.eq(coll.find(index1.doc).hint(index1.index.name).itcount(), 1);
        assert.eq(coll.find(index1.doc).hint(index2.index.name).itcount(), 0);
    }

    // Check index 2 document.
    if (index2.hasOwnProperty('doc')) {
        assert.commandWorked(coll.insert(index2.doc));
        assert.eq(coll.find(index2.doc).hint(index2.index.name).itcount(), 1);
        assert.eq(coll.find(index2.doc).hint(index1.index.name).itcount(), 0);
    }

    // Check for present of both in both index1 and index2.
    if (typeof both !== "undefined") {
        assert.commandWorked(coll.insert(both));
        assert.eq(coll.find(both).hint(index1.index.name).itcount(), 1);
        assert.eq(coll.find(both).hint(index2.index.name).itcount(), 1);
    }

    // Remove index 1 document.
    if (index1.hasOwnProperty('doc')) {
        assert.commandWorked(coll.remove(index1.doc));
        assert.eq(coll.find(index1.doc).hint(index1.index.name).itcount(), 0);
    }

    // Remove index 2 document.
    if (index2.hasOwnProperty('doc')) {
        assert.commandWorked(coll.remove(index2.doc));
        assert.eq(coll.find(index2.doc).hint(index2.index.name).itcount(), 0);
    }

    // Remove both.
    if (typeof both !== "undefined") {
        assert.commandWorked(coll.remove(both));
        assert.eq(coll.find(both).hint(index1.index.name).itcount(), 0);
        assert.eq(coll.find(both).hint(index2.index.name).itcount(), 0);
    }
}

// Two identical partial indexes.
testIndexCompat(coll,
                {
                    index: {
                        key: {a: 1},
                        name: "a1",
                        collation: enUSStrength1,
                        partialFilterExpression: {a: {$type: 'string'}}
                    }
                },
                {
                    index: {
                        key: {a: 1},
                        name: "a2",
                        collation: enUSStrength2,
                        partialFilterExpression: {a: {$type: 'string'}}
                    }
                },
                {a: "A"});

// Two non-overlapping partial indexes.
testIndexCompat(coll,
                {
                    index: {
                        key: {a: 1},
                        name: "a1",
                        collation: enUSStrength1,
                        partialFilterExpression: {a: {$lt: 10}}
                    },
                    doc: {a: 5}
                },
                {
                    index: {
                        key: {a: 1},
                        name: "a2",
                        collation: enUSStrength2,
                        partialFilterExpression: {a: {$gt: 20}}
                    },
                    doc: {a: 25}
                });

// Two partially overlapping partial indexes.
testIndexCompat(coll,
                {
                    index: {
                        key: {a: 1},
                        name: "a1",
                        collation: enUSStrength1,
                        partialFilterExpression: {a: {$lt: 10}},
                    },
                    doc: {a: -5}
                },
                {
                    index: {
                        key: {a: 1},
                        name: "a2",
                        collation: enUSStrength2,
                        partialFilterExpression: {a: {$gte: 0}}
                    },
                    doc: {a: 15}
                },
                {a: 5});

// A partial and sparse index.
testIndexCompat(
    coll,
    {
        index: {key: {a: 1}, name: "a1", collation: enUSStrength1, partialFilterExpression: {b: 0}},
        doc: {b: 0}
    },
    {index: {key: {a: 1}, name: "a2", collation: enUSStrength2, sparse: true}, doc: {a: 5, b: 1}},
    {a: -1, b: 0});

// A sparse and non-sparse index.
testIndexCompat(
    coll,
    {
        index: {key: {a: 1}, name: "a1", collation: enUSStrength1, sparse: true},
    },
    {index: {key: {a: 1}, name: "a2", collation: enUSStrength2, sparse: false}, doc: {b: 0}},
    {a: 1});

// A unique index and non-unique index.
testIndexCompat(coll,
                {
                    index: {key: {a: 1}, name: "unique", collation: enUSStrength1, unique: true},
                },
                {index: {key: {a: 1}, name: "reg", collation: enUSStrength2, unique: false}},
                {a: "foo"});

// Test that unique constraints are still enforced.
assert.commandWorked(coll.insert({a: "f"}));
assert.writeError(coll.insert({a: "F"}));

// A unique partial index and non-unique index.
testIndexCompat(
    coll,
    {
        index: {
            key: {a: 1},
            name: "unique",
            collation: enUSStrength1,
            unique: true,
            partialFilterExpression: {a: {$type: 'number'}}
        }
    },
    {index: {key: {a: 1}, name: "a", collation: enUSStrength2, unique: false}, doc: {a: "foo"}},
    {a: 5});

assert.commandWorked(coll.insert({a: 5}));
// Test that uniqueness is only enforced by the partial index.
assert.commandWorked(coll.insert({a: "foo"}));
assert.commandWorked(coll.insert({a: "foo"}));
assert.writeError(coll.insert({a: 5}));

// Two unique indexes with different collations.
testIndexCompat(coll,
                {index: {key: {a: 1}, name: "a1", collation: enUSStrength1, unique: true}},
                {index: {key: {a: 1}, name: "a2", collation: enUSStrength3, unique: true}},
                {a: "a"});

// Unique enforced on both indexes.
assert.commandWorked(coll.insert({a: "a"}));
assert.writeError(coll.insert({a: "a"}));
assert.writeError(coll.insert({a: "A"}));

// A unique and sparse index.
testIndexCompat(
    coll,
    {
        index: {key: {a: 1}, name: "a1", collation: enUSStrength1, unique: true, sparse: true},
    },
    {index: {key: {a: 1}, name: "a2", collation: enUSStrength2, unique: false}, doc: {b: 0}},
    {a: "a"});

assert.commandWorked(coll.insert({a: "a"}));
assert.commandWorked(coll.insert({}));
assert.commandWorked(coll.insert({}));
assert.writeError(coll.insert({a: "a"}));
})();