mirror of https://github.com/mongodb/mongo
115 lines
4.3 KiB
JavaScript
115 lines
4.3 KiB
JavaScript
/**
|
|
* Tests to verify that hashed indexes obey collation rules.
|
|
*
|
|
* The tags below are necessary because collation requires that we use read/write commands rather
|
|
* than legacy operations.
|
|
* @tags: [requires_find_command, assumes_unsharded_collection, requires_fcv_44]
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
load("jstests/aggregation/extras/utils.js"); // For arrayEq().
|
|
load("jstests/libs/analyze_plan.js"); // For assertStagesForExplainOfCommand().
|
|
|
|
const coll = db.hashed_index_collation;
|
|
coll.drop();
|
|
const collation = {
|
|
locale: "en_US",
|
|
strength: 1
|
|
};
|
|
|
|
/**
|
|
* Runs find command with the 'filter' and 'projection' provided in the input, then validates
|
|
* that the output returned matches 'expectedOutput'. Also runs explain() command on the same find
|
|
* command, validates that all the 'expectedStages' are present in the plan returned and all the
|
|
* 'stagesNotExpected' are not present in the plan.
|
|
*/
|
|
function validateFindCmdOutputAndPlan(
|
|
{filter, projection = {}, expectedOutput, expectedStages, stagesNotExpected}) {
|
|
const cmdObj =
|
|
{find: coll.getName(), filter: filter, projection: projection, collation: collation};
|
|
const res = assert.commandWorked(coll.runCommand(cmdObj));
|
|
const ouputArray = new DBCommandCursor(coll.getDB(), res).toArray();
|
|
|
|
// We ignore the order since hashed index order is not predictable.
|
|
assert(arrayEq(expectedOutput, ouputArray), ouputArray);
|
|
|
|
assertStagesForExplainOfCommand({
|
|
coll: coll,
|
|
cmdObj: cmdObj,
|
|
expectedStages: expectedStages,
|
|
stagesNotExpected: stagesNotExpected
|
|
});
|
|
}
|
|
|
|
// Verify that index creation works for compound hashed index with collation, when hashed field is a
|
|
// prefix.
|
|
assert.commandWorked(
|
|
coll.createIndex({"a.b": "hashed", "a.c": 1, "a.e": -1}, {collation: collation}));
|
|
|
|
// Insert a series of documents whose fieldnames and values differ only by case.
|
|
assert.commandWorked(coll.insert({_id: 0, a: {b: "string", c: "STRING", e: 5}}));
|
|
assert.commandWorked(coll.insert({_id: 1, a: {b: "STRING", c: "string", e: 5}}));
|
|
assert.commandWorked(coll.insert({_id: 2, A: {B: "string", C: "STRING", E: 5}}));
|
|
assert.commandWorked(coll.insert({_id: 3, A: {B: "StrinG", C: "sTRINg", E: 5}}));
|
|
|
|
// Verify that hashed field can use index in the presence of collation. Also verify that only
|
|
// the document's values, not the field names, adhere to the case-insensitive collation.
|
|
validateFindCmdOutputAndPlan({
|
|
filter: {"a.b": "string", "a.c": "string"},
|
|
expectedStages: ["IXSCAN", "FETCH"],
|
|
expectedOutput: [
|
|
{_id: 0, a: {b: "string", c: "STRING", e: 5}},
|
|
{_id: 1, a: {b: "STRING", c: "string", e: 5}}
|
|
]
|
|
});
|
|
|
|
// Verify that the field names doesn't adhere to the case-insensitive collation and uses collection
|
|
// scan if the case doesn't match.
|
|
validateFindCmdOutputAndPlan({
|
|
filter: {"A.B": "string"},
|
|
expectedStages: ["COLLSCAN"],
|
|
expectedOutput: [
|
|
{_id: 2, A: {B: "string", C: "STRING", E: 5}},
|
|
{_id: 3, A: {B: "StrinG", C: "sTRINg", E: 5}}
|
|
]
|
|
});
|
|
|
|
// Verify that $or query with collation returns correct results.
|
|
validateFindCmdOutputAndPlan({
|
|
filter: {$or: [{"a.b": "string_1"}, {"a.b": "string", "a.c": "string"}]},
|
|
expectedStages: ["OR"],
|
|
stagesNotExpected: ["COLLSCAN"], // Verify that both the OR stages use index scan.
|
|
expectedOutput: [
|
|
{_id: 0, a: {b: "string", c: "STRING", e: 5}},
|
|
{_id: 1, a: {b: "STRING", c: "string", e: 5}}
|
|
]
|
|
});
|
|
|
|
/**
|
|
* When hashed field is not a prefix.
|
|
*/
|
|
assert.commandWorked(coll.dropIndexes());
|
|
assert.commandWorked(
|
|
coll.createIndex({"a.b": 1, "a.c": "hashed", "a.e": -1}, {collation: collation}));
|
|
|
|
// Hashed indexes with collation can be covered, if the query predicate restrict strings from being
|
|
// returned.
|
|
validateFindCmdOutputAndPlan({
|
|
filter: {"a.b": "string", "a.e": {$type: "number"}},
|
|
projection: {"a.e": 1, _id: 0},
|
|
expectedStages: ["IXSCAN"],
|
|
stagesNotExpected: ["FETCH"],
|
|
expectedOutput: [{a: {e: 5}}, {a: {e: 5}}]
|
|
});
|
|
|
|
// Hashed indexes with collation cannot be covered, if the query predicate doesn't restrict strings
|
|
// from being returneds.
|
|
validateFindCmdOutputAndPlan({
|
|
filter: {"a.b": "string"},
|
|
projection: {"a.e": 1, _id: 0},
|
|
expectedStages: ["IXSCAN", "FETCH"],
|
|
expectedOutput: [{a: {e: 5}}, {a: {e: 5}}]
|
|
});
|
|
})();
|