189 lines
5.7 KiB
JavaScript
189 lines
5.7 KiB
JavaScript
// Check $match pipeline stage.
|
|
// - Filtering behavior equivalent to a mongo query.
|
|
// - $where and geo operators are not allowed
|
|
load('jstests/aggregation/extras/utils.js');
|
|
|
|
t = db.jstests_aggregation_match;
|
|
t.drop();
|
|
|
|
identityProjection = {
|
|
_id: '$_id',
|
|
a: '$a'
|
|
};
|
|
|
|
/** Assert that an aggregation generated the expected error. */
|
|
function assertError(expectedCode, matchSpec) {
|
|
matchStage = {$match: matchSpec};
|
|
// Check where matching is folded in to DocumentSourceCursor.
|
|
assertErrorCode(t, [matchStage], expectedCode);
|
|
// Check where matching is not folded in to DocumentSourceCursor.
|
|
assertErrorCode(t, [{$project: identityProjection}, matchStage], expectedCode);
|
|
}
|
|
|
|
/** Assert that the contents of two arrays are equal, ignoring element ordering. */
|
|
function assertEqualResultsUnordered(one, two) {
|
|
oneStr = one.map(function(x) {
|
|
return tojson(x);
|
|
});
|
|
twoStr = two.map(function(x) {
|
|
return tojson(x);
|
|
});
|
|
oneStr.sort();
|
|
twoStr.sort();
|
|
assert.eq(oneStr, twoStr);
|
|
}
|
|
|
|
/** Assert that an aggregation result is as expected. */
|
|
function assertResults(expectedResults, matchSpec) {
|
|
findResults = t.find(matchSpec).toArray();
|
|
if (expectedResults) {
|
|
assertEqualResultsUnordered(expectedResults, findResults);
|
|
}
|
|
matchStage = {$match: matchSpec};
|
|
// Check where matching is folded in to DocumentSourceCursor.
|
|
assertEqualResultsUnordered(findResults, t.aggregate(matchStage).toArray());
|
|
// Check where matching is not folded in to DocumentSourceCursor.
|
|
assertEqualResultsUnordered(findResults,
|
|
t.aggregate({$project: identityProjection}, matchStage).toArray());
|
|
}
|
|
|
|
// Invalid matcher syntax.
|
|
assertError(2, {a: {$mod: [0 /* invalid */, 0]}});
|
|
|
|
// $where not allowed.
|
|
assertError(16395, {$where: 'true'});
|
|
|
|
// Geo not allowed.
|
|
assertError(16424, {$match: {a: {$near: [0, 0]}}});
|
|
|
|
// Update modifier not allowed.
|
|
if (0) { // SERVER-6650
|
|
assertError(0, {a: 1, $inc: {b: 1}});
|
|
}
|
|
|
|
// Aggregation expression not allowed.
|
|
if (0) { // SERVER-6650
|
|
assertError(0, {a: 1, b: {$gt: {$add: [1, 1]}}});
|
|
}
|
|
|
|
function checkMatchResults(indexed) {
|
|
// No results.
|
|
t.remove({});
|
|
assertResults([], {});
|
|
|
|
t.save({_id: 0, a: 1});
|
|
t.save({_id: 1, a: 2});
|
|
t.save({_id: 2, a: 3});
|
|
|
|
// Empty query.
|
|
assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}, {_id: 2, a: 3}], {});
|
|
|
|
// Simple queries.
|
|
assertResults([{_id: 0, a: 1}], {a: 1});
|
|
assertResults([{_id: 1, a: 2}], {a: 2});
|
|
assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}], {a: {$gt: 1}});
|
|
assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}], {a: {$lte: 2}});
|
|
assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {a: {$in: [1, 3]}});
|
|
|
|
// Regular expression.
|
|
t.remove({});
|
|
t.save({_id: 0, a: 'x'});
|
|
t.save({_id: 1, a: 'yx'});
|
|
assertResults([{_id: 0, a: 'x'}], {a: /^x/});
|
|
assertResults([{_id: 0, a: 'x'}, {_id: 1, a: 'yx'}], {a: /x/});
|
|
|
|
// Dotted field.
|
|
t.remove({});
|
|
t.save({_id: 0, a: {b: 4}});
|
|
t.save({_id: 1, a: 2});
|
|
assertResults([{_id: 0, a: {b: 4}}], {'a.b': 4});
|
|
|
|
// Value within an array.
|
|
t.remove({});
|
|
t.save({_id: 0, a: [1, 2, 3]});
|
|
t.save({_id: 1, a: [2, 2, 3]});
|
|
t.save({_id: 2, a: [2, 2, 2]});
|
|
assertResults([{_id: 0, a: [1, 2, 3]}, {_id: 1, a: [2, 2, 3]}], {a: 3});
|
|
|
|
// Missing, null, $exists matching.
|
|
t.remove({});
|
|
t.save({_id: 0});
|
|
t.save({_id: 1, a: null});
|
|
if (0) { // SERVER-6571
|
|
t.save({_id: 2, a: undefined});
|
|
}
|
|
t.save({_id: 3, a: 0});
|
|
assertResults([{_id: 0}, {_id: 1, a: null}], {a: null});
|
|
assertResults(null, {a: {$exists: true}});
|
|
assertResults(null, {a: {$exists: false}});
|
|
|
|
// $elemMatch
|
|
t.remove({});
|
|
t.save({_id: 0, a: [1, 2]});
|
|
t.save({_id: 1, a: [1, 2, 3]});
|
|
assertResults([{_id: 1, a: [1, 2, 3]}], {a: {$elemMatch: {$gt: 1, $mod: [2, 1]}}});
|
|
|
|
t.remove({});
|
|
t.save({_id: 0, a: [{b: 1}, {c: 2}]});
|
|
t.save({_id: 1, a: [{b: 1, c: 2}]});
|
|
assertResults([{_id: 1, a: [{b: 1, c: 2}]}], {a: {$elemMatch: {b: 1, c: 2}}});
|
|
|
|
// $size
|
|
t.remove({});
|
|
t.save({});
|
|
t.save({a: null});
|
|
t.save({a: []});
|
|
t.save({a: [1]});
|
|
t.save({a: [1, 2]});
|
|
assertResults(null, {a: {$size: 0}});
|
|
assertResults(null, {a: {$size: 1}});
|
|
assertResults(null, {a: {$size: 2}});
|
|
|
|
// $type
|
|
t.remove({});
|
|
t.save({});
|
|
t.save({a: null});
|
|
if (0) { // SERVER-6571
|
|
t.save({a: undefined});
|
|
}
|
|
t.save({a: NumberInt(1)});
|
|
t.save({a: NumberLong(2)});
|
|
t.save({a: 66.6});
|
|
t.save({a: 'abc'});
|
|
t.save({a: /xyz/});
|
|
t.save({a: {q: 1}});
|
|
t.save({a: true});
|
|
t.save({a: new Date()});
|
|
t.save({a: new ObjectId()});
|
|
for (type = 1; type <= 18; ++type) {
|
|
assertResults(null, {a: {$type: type}});
|
|
}
|
|
|
|
// $atomic does not affect results.
|
|
t.remove({});
|
|
t.save({_id: 0, a: 1});
|
|
t.save({_id: 1, a: 2});
|
|
t.save({_id: 2, a: 3});
|
|
assertResults([{_id: 0, a: 1}], {a: 1, $atomic: true});
|
|
assertResults([{_id: 1, a: 2}], {a: 2, $atomic: true});
|
|
assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}], {a: {$gt: 1}, $atomic: true});
|
|
assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}], {a: {$lte: 2}, $atomic: true});
|
|
assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {a: {$in: [1, 3]}, $atomic: true});
|
|
|
|
// $and
|
|
assertResults([{_id: 1, a: 2}], {$and: [{a: 2}, {_id: 1}]});
|
|
assertResults([], {$and: [{a: 1}, {_id: 1}]});
|
|
assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}],
|
|
{$and: [{$or: [{_id: 1}, {a: 3}]}, {$or: [{_id: 2}, {a: 2}]}]});
|
|
|
|
// $or
|
|
assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {$or: [{_id: 0}, {a: 3}]});
|
|
}
|
|
|
|
checkMatchResults(false);
|
|
t.ensureIndex({a: 1});
|
|
checkMatchResults(true);
|
|
t.ensureIndex({'a.b': 1});
|
|
t.ensureIndex({'a.c': 1});
|
|
checkMatchResults(true);
|