diff options
-rw-r--r-- | db/jsobj.cpp | 2 | ||||
-rw-r--r-- | db/jsobj.h | 1 | ||||
-rw-r--r-- | db/matcher.cpp | 14 | ||||
-rw-r--r-- | db/matcher.h | 13 | ||||
-rw-r--r-- | db/queryutil.cpp | 81 | ||||
-rw-r--r-- | jstests/fm2.js | 9 | ||||
-rw-r--r-- | jstests/mod1.js | 16 | ||||
-rw-r--r-- | shell/dbshell.cpp | 4 |
8 files changed, 98 insertions, 42 deletions
diff --git a/db/jsobj.cpp b/db/jsobj.cpp index bf44e9370cc..b872239310e 100644 --- a/db/jsobj.cpp +++ b/db/jsobj.cpp @@ -411,6 +411,8 @@ namespace mongo { if ( fn[1] == 'n' && fn[3] == 0 ) return BSONObj::NE; } + else if ( fn[1] == 'm' && fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0 ) + return BSONObj::opMOD; else if ( fn[1] == 'i' && fn[2] == 'n' && fn[3] == 0 ) return BSONObj::opIN; else if ( fn[1] == 'n' && fn[2] == 'i' && fn[3] == 'n' && fn[4] == 0 ) diff --git a/db/jsobj.h b/db/jsobj.h index 9fd2a1b88ec..711c539a2a7 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -901,6 +901,7 @@ namespace mongo { opALL = 0x0B, NIN = 0x0C, opEXISTS = 0x0D, + opMOD = 0x0E }; }; ostream& operator<<( ostream &s, const BSONObj &o ); diff --git a/db/matcher.cpp b/db/matcher.cpp index bc6792c7e67..fac352a1d60 100644 --- a/db/matcher.cpp +++ b/db/matcher.cpp @@ -246,6 +246,11 @@ namespace mongo { basics.push_back( BasicMatcher( e , BSONObj::opIN , fe.embeddedObject() ) ); ok = true; } + else if ( fn[1] == 'm' && fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0 && fe.type() == Array ) { + // $mod + basics.push_back( BasicMatcher( e , BSONObj::opMOD ) ); + ok = true; + } else if ( fn[1] == 'n' && fn[2] == 'i' && fn[3] == 'n' && fn[4] == 0 && fe.type() == Array ) { // $nin basics.push_back( BasicMatcher( e , BSONObj::NIN , fe.embeddedObject() ) ); @@ -315,7 +320,14 @@ namespace mongo { } return count == r.number(); } - + + if ( op == BSONObj::opMOD ){ + if ( ! l.isNumber() ) + return false; + + return l.numberLong() % bm.mod == bm.modm; + } + /* check LT, GTE, ... */ if ( !( l.isNumber() && r.isNumber() ) && ( l.type() != r.type() ) ) return false; diff --git a/db/matcher.h b/db/matcher.h index c814fe3c2cb..03b5b335845 100644 --- a/db/matcher.h +++ b/db/matcher.h @@ -57,9 +57,17 @@ namespace mongo { } BasicMatcher( BSONElement _e , int _op ) : toMatch( _e ) , compareOp( _op ){ + if ( _op == BSONObj::opMOD ){ + BSONObj o = _e.embeddedObject().firstElement().embeddedObject(); + mod = o["0"].numberInt(); + modm = o["1"].numberInt(); + + uassert( "mod can't be 0" , mod ); + uassert( "mod eq can't be 0" , modm ); + } } - + BasicMatcher( BSONElement _e , int _op , const BSONObj& array ) : toMatch( _e ) , compareOp( _op ){ myset.reset( new set<BSONElement,element_lt>() ); @@ -74,6 +82,9 @@ namespace mongo { BSONElement toMatch; int compareOp; shared_ptr< set<BSONElement,element_lt> > myset; + + int mod; + int modm; }; // SQL where clause equivalent diff --git a/db/queryutil.cpp b/db/queryutil.cpp index 4a99736ddac..a4d44f9e965 100644 --- a/db/queryutil.cpp +++ b/db/queryutil.cpp @@ -23,7 +23,7 @@ #include "queryoptimizer.h" namespace mongo { - + FieldRange::FieldRange( const BSONElement &e, bool optimize ) { lower() = minKey.firstElement(); lowerInclusive() = true; @@ -41,49 +41,52 @@ namespace mongo { return; } switch( e.getGtLtOp() ) { - case BSONObj::Equality: - lower() = e; - upper() = e; - break; - case BSONObj::LT: - upperInclusive() = false; - case BSONObj::LTE: - upper() = e; - break; - case BSONObj::GT: - lowerInclusive() = false; - case BSONObj::GTE: - lower() = e; - break; + case BSONObj::Equality: + lower() = e; + upper() = e; + break; + case BSONObj::LT: + upperInclusive() = false; + case BSONObj::LTE: + upper() = e; + break; + case BSONObj::GT: + lowerInclusive() = false; + case BSONObj::GTE: + lower() = e; + break; case BSONObj::opALL: { massert( "$all requires array", e.type() == Array ); - BSONObjIterator i( e.embeddedObject() ); - if ( i.moreWithEOO() ) { - BSONElement f = i.next(); - if ( !f.eoo() ) - lower() = upper() = f; - } - break; + BSONObjIterator i( e.embeddedObject() ); + if ( i.moreWithEOO() ) { + BSONElement f = i.next(); + if ( !f.eoo() ) + lower() = upper() = f; + } + break; } + case BSONObj::opMOD: { + break; + } case BSONObj::opIN: { - massert( "$in requires array", e.type() == Array ); - BSONElement max = minKey.firstElement(); - BSONElement min = maxKey.firstElement(); - BSONObjIterator i( e.embeddedObject() ); - while( i.moreWithEOO() ) { - BSONElement f = i.next(); - if ( f.eoo() ) - break; - if ( max.woCompare( f, false ) < 0 ) - max = f; - if ( min.woCompare( f, false ) > 0 ) - min = f; - } - lower() = min; - upper() = max; + massert( "$in requires array", e.type() == Array ); + BSONElement max = minKey.firstElement(); + BSONElement min = maxKey.firstElement(); + BSONObjIterator i( e.embeddedObject() ); + while( i.moreWithEOO() ) { + BSONElement f = i.next(); + if ( f.eoo() ) + break; + if ( max.woCompare( f, false ) < 0 ) + max = f; + if ( min.woCompare( f, false ) > 0 ) + min = f; } - default: - break; + lower() = min; + upper() = max; + } + default: + break; } if ( optimize ){ diff --git a/jstests/fm2.js b/jstests/fm2.js new file mode 100644 index 00000000000..bee89300db3 --- /dev/null +++ b/jstests/fm2.js @@ -0,0 +1,9 @@ + +t = db.fm2 +t.drop(); + +t.insert( { "one" : { "two" : {"three":"four"} } } ); + +x = t.find({},{"one.two":1})[0] +assert.eq( 1 , x.one.keySet().length , "ks l 1" ); + diff --git a/jstests/mod1.js b/jstests/mod1.js new file mode 100644 index 00000000000..c77b5091e89 --- /dev/null +++ b/jstests/mod1.js @@ -0,0 +1,16 @@ + +t = db.mod1; +t.drop(); + +t.save( { a : 1 } ); +t.save( { a : 2 } ); +t.save( { a : 11 } ); + +assert.eq( 2 , t.find( "this.a % 10 == 1" ).itcount() , "A" ); +assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "B" ); + +t.ensureIndex( { a : 1 } ); + +assert.eq( 2 , t.find( "this.a % 10 == 1" ).itcount() , "C" ); +assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "D" ); + diff --git a/shell/dbshell.cpp b/shell/dbshell.cpp index f6208518d52..1f09709c278 100644 --- a/shell/dbshell.cpp +++ b/shell/dbshell.cpp @@ -301,7 +301,7 @@ int _main(int argc, char* argv[]) { if ( line ) while ( line[0] == ' ' ) line++; - + if ( ! line || ( strlen(line) == 4 && strstr( line , "exit" ) ) ){ cout << "bye" << endl; break; @@ -311,6 +311,8 @@ int _main(int argc, char* argv[]) { if ( code == "exit" ){ break; } + if ( code.size() == 0 ) + continue; bool wascmd = false; { |