// 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"})); })();