Changes: * Date and Timestamp are now distinct with all Dates before all Timestamps. * Numeric comparisons now correctly handle Doubles and Long > 2**53. * CodeWScope doesn't strcmp BSONObjs or strings which may contain NULs. There should be no changes in any of the cases where woCompare defined a correct total ordering before. The new behavior matches the ordering defined by KeyString. Related tickets: * SERVER-3304 Error comparing Date and Timestamp * SERVER-3719 Total ordering over Longs and Doubles * SERVER-7804 CodeWScope comparisons are broken * SERVER-16632 Change WiredTiger index key format Changes to the comparison function for aggregation will be handled separately as SERVER-16708.
184 lines
6.1 KiB
JavaScript
184 lines
6.1 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( 16810, { 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 );
|