Files
mongo/jstests/aggregation/bugs/match.js
Mathias Stearn f58fa5f78a Make BSONObj::woCompare a total ordering
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.
2015-01-07 11:56:33 -05:00

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 );