mirror of https://github.com/mongodb/mongo
210 lines
5.5 KiB
JavaScript
210 lines
5.5 KiB
JavaScript
// SERVER-6146 introduced the $in expression to aggregation. In this file, we test the functionality
|
|
// and error cases of the expression.
|
|
// @tags: [
|
|
// assumes_no_implicit_collection_creation_after_drop,
|
|
// ]
|
|
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
|
|
|
|
(function() {
|
|
"use strict";
|
|
|
|
const caseInsensitive = {
|
|
locale: "en_US",
|
|
strength: 2
|
|
};
|
|
var coll = db.in;
|
|
coll.drop();
|
|
|
|
function testExpression(options) {
|
|
coll.drop();
|
|
testExpressionInternal(options);
|
|
}
|
|
|
|
function testExpressionHashIndex(options) {
|
|
coll.drop();
|
|
assert.commandWorked(coll.createIndex({elementField: "hashed"}));
|
|
testExpressionInternal(options);
|
|
}
|
|
|
|
function testExpressionCollectionCollation(options, collationSpec) {
|
|
coll.drop();
|
|
assert.commandWorked(db.createCollection(coll.getName(), {collation: collationSpec}));
|
|
testExpressionInternal(options);
|
|
}
|
|
|
|
function testExpressionInternal(options) {
|
|
var pipeline = {$project: {included: {$in: ["$elementField", {$literal: options.array}]}}};
|
|
assert.commandWorked(coll.insert({elementField: options.element}));
|
|
var res = coll.aggregate(pipeline).toArray();
|
|
assert.eq(res.length, 1);
|
|
assert.eq(res[0].included, options.elementIsIncluded);
|
|
|
|
if (options.queryFormShouldBeEquivalent) {
|
|
var query = {elementField: {$in: options.array}};
|
|
res = coll.find(query).toArray();
|
|
|
|
if (options.elementIsIncluded) {
|
|
assert.eq(res.length, 1);
|
|
} else {
|
|
assert.eq(res.length, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
testExpression(
|
|
{element: 1, array: [1, 2, 3], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
|
|
|
|
testExpression({
|
|
element: "A",
|
|
array: ["a", "A", "a"],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
testExpression({
|
|
element: {a: 1},
|
|
array: [{b: 1}, 2],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
testExpression(
|
|
{element: {a: 1}, array: [{a: 1}], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
|
|
|
|
testExpression({
|
|
element: [1, 2],
|
|
array: [[2, 1]],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
testExpression(
|
|
{element: [1, 2], array: [[1, 2]], elementIsIncluded: true, queryFormShouldBeEquivalent: true});
|
|
|
|
// Test $in with duplicated target element.
|
|
testExpression({
|
|
element: 7,
|
|
array: [3, 5, 7, 7, 9],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
// Test $in with other element within array duplicated.
|
|
testExpression({
|
|
element: 7,
|
|
array: [3, 5, 7, 9, 9],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
// Test $in on unsorted array.
|
|
testExpression({
|
|
element: 7,
|
|
array: [3, 10, 5, 7, 8, 9],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
// Test matching $in on unsorted array with duplicates.
|
|
testExpression({
|
|
element: 7,
|
|
array: [7, 10, 7, 10, 2, 5, 3, 7],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
// Test non-matching $in on unsorted array with duplicates.
|
|
testExpression({
|
|
element: 8,
|
|
array: [10, 7, 2, 5, 3],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
// Test $in with success due to collation on source collection.
|
|
testExpressionCollectionCollation({
|
|
element: "abcd",
|
|
array: ["aBcD", "ABCD"],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
},
|
|
caseInsensitive);
|
|
|
|
// Test $in with a source collection that has a hash index on the relevant field.
|
|
testExpressionHashIndex({
|
|
element: 5,
|
|
array: [10, 7, 2, 5, 3],
|
|
elementIsIncluded: true,
|
|
queryFormShouldBeEquivalent: true
|
|
});
|
|
|
|
testExpression(
|
|
{element: 1, array: [], elementIsIncluded: false, queryFormShouldBeEquivalent: true});
|
|
|
|
// Aggregation's $in has parity with query's $in except with regexes matching string values and
|
|
// equality semantics with array values.
|
|
|
|
testExpression({
|
|
element: "abc",
|
|
array: [/a/, /b/, /c/],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: false
|
|
});
|
|
|
|
testExpression({
|
|
element: /a/,
|
|
array: ["a", "b", "c"],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: false
|
|
});
|
|
|
|
testExpression(
|
|
{element: [], array: [1, 2, 3], elementIsIncluded: false, queryFormShouldBeEquivalent: false});
|
|
|
|
testExpression(
|
|
{element: [1], array: [1, 2, 3], elementIsIncluded: false, queryFormShouldBeEquivalent: false});
|
|
|
|
testExpression({
|
|
element: [1, 2],
|
|
array: [1, 2, 3],
|
|
elementIsIncluded: false,
|
|
queryFormShouldBeEquivalent: false
|
|
});
|
|
|
|
coll.drop();
|
|
coll.insert({});
|
|
|
|
var pipeline = {$project: {included: {$in: [[1, 2], 1]}}};
|
|
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: [1, null]}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: [1, "$notAField"]}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 40081, "$in requires an array as a second argument");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: null}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: [1]}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: []}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
|
|
|
|
pipeline = {
|
|
$project: {included: {$in: [1, 2, 3]}}
|
|
};
|
|
assertErrorCode(coll, pipeline, 16020, "$in requires two arguments");
|
|
}());
|