0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00

$addToSet mostly working SERVER-176

This commit is contained in:
Eliot Horowitz 2010-01-26 17:29:06 -05:00
parent ca42b6de8a
commit 556c5a6d7d
3 changed files with 74 additions and 5 deletions

View File

@ -27,7 +27,7 @@
namespace mongo {
const char* Mod::modNames[] = { "$inc", "$set", "$push", "$pushAll", "$pull", "$pullAll" , "$pop", "$unset" ,
"$bitand" , "$bitor" , "$bit" };
"$bitand" , "$bitor" , "$bit" , "$addToSet" };
unsigned Mod::modNamesNum = sizeof(Mod::modNames)/sizeof(char*);
bool Mod::_pullElementMatch( BSONElement& toMatch ) const {
@ -85,7 +85,7 @@ namespace mongo {
//Explicit NOOP
break;
}
case PUSH: {
uassert( 10131 , "$push can only be applied to an array" , in.type() == Array );
BSONObjBuilder bb( b.subarrayStart( shortFieldName ) );
@ -102,6 +102,30 @@ namespace mongo {
bb.done();
break;
}
case ADDTOSET: {
uassert( 12592 , "$addToSet can only be applied to an array" , in.type() == Array );
BSONObjBuilder bb( b.subarrayStart( shortFieldName ) );
BSONObjIterator i( in.embeddedObject() );
bool found = false;
int n=0;
while ( i.more() ){
BSONElement cur = i.next();
bb.append( cur );
n++;
if ( elt.woCompare( cur , false ) == 0 )
found = true;
}
if ( ! found )
bb.appendAs( elt , bb.numStr( n ) );
bb.done();
break;
}
case PUSH_ALL: {
uassert( 10132 , "$pushAll can only be applied to an array" , in.type() == Array );
@ -274,15 +298,18 @@ namespace mongo {
}
}
break;
case Mod::SET:
mss->amIInPlacePossible( m.elt.type() == e.type() &&
m.elt.valuesize() == e.valuesize() );
break;
case Mod::PUSH:
case Mod::PUSH_ALL:
uassert( 10141 , "Cannot apply $push/$pushAll modifier to non-array", e.type() == Array || e.eoo() );
mss->amIInPlacePossible( false );
break;
case Mod::PULL:
case Mod::PULL_ALL: {
uassert( 10142 , "Cannot apply $pull/$pullAll modifier to non-array", e.type() == Array || e.eoo() );
@ -304,11 +331,29 @@ namespace mongo {
}
break;
}
case Mod::POP: {
uassert( 10143 , "Cannot apply $pop modifier to non-array", e.type() == Array || e.eoo() );
mss->amIInPlacePossible( e.embeddedObject().isEmpty() );
break;
}
case Mod::ADDTOSET: {
uassert( 12591 , "Cannot apply $addToSet modifier to non-array", e.type() == Array || e.eoo() );
BSONObjIterator i( e.embeddedObject() );
bool found = false;
while( i.more() ) {
BSONElement arrI = i.next();
if ( arrI.woCompare( m.elt , false ) == 0 ){
found = true;
break;
}
}
mss->amIInPlacePossible( found );
break;
}
default:
// mods we don't know about shouldn't be done in place
mss->amIInPlacePossible( false );
@ -325,6 +370,7 @@ namespace mongo {
case Mod::UNSET:
case Mod::PULL:
case Mod::PULL_ALL:
case Mod::ADDTOSET:
// this should have been handled by prepare
break;

View File

@ -32,8 +32,8 @@ namespace mongo {
*/
struct Mod {
// See opFromStr below
// 0 1 2 3 4 5 6 7 8 9 10
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BITAND, BITOR , BIT } op;
// 0 1 2 3 4 5 6 7 8 9 10 11
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BITAND, BITOR , BIT , ADDTOSET } op;
static const char* modNames[];
static unsigned modNamesNum;
@ -160,7 +160,7 @@ namespace mongo {
return compareDottedFieldNames( m->first, p->first.c_str() );
}
bool mayAddEmbedded( map< string, BSONElement > &existing, string right ) {
for( string left = EmbeddedBuilder::splitDot( right );
left.length() > 0 && left[ left.length() - 1 ] != '.';
@ -220,6 +220,14 @@ namespace mongo {
}
break;
}
case 'a': {
if ( fn[2] == 'd' && fn[3] == 'd' ){
// add
if ( fn[4] == 'T' && fn[5] == 'o' && fn[6] == 'S' && fn[7] == 'e' && fn[8] == 't' && fn[9] == 0 )
return Mod::ADDTOSET;
}
}
default: break;
}
uassert( 10161 , "Invalid modifier specified " + string( fn ), false );

View File

@ -0,0 +1,15 @@
t = db.update_addToSet1;
t.drop();
o = { _id : 1 , a : [ 2 , 1 ] }
t.insert( o );
assert.eq( o , t.findOne() , "A1" );
t.update( {} , { $addToSet : { a : 3 } } );
o.a.push( 3 );
assert.eq( o , t.findOne() , "A2" );
t.update( {} , { $addToSet : { a : 3 } } );
assert.eq( o , t.findOne() , "A3" );