[SERVER-390] upsert with x.y query misinterpreted by server Created: 27/Oct/09  Updated: 12/Jul/16  Resolved: 16/Jan/10

Status: Closed
Project: Core Server
Component/s: Write Ops
Affects Version/s: 1.0.0
Fix Version/s: 1.3.1

Type: Bug Priority: Major - P3
Reporter: Jason Sachs Assignee: Eliot Horowitz (Inactive)
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
is depended on by SERVER-453 $iset - set fields only on insert whe... Closed
Related
related to SERVER-492 when doing upsert with $filter, don't... Closed
Participants:

 Description   

Looks like one of the upsert syntaxes is misinterpreted on the server
(seems to be a server bug rather than a shell bug, I get the same
behavior in the Java driver). Before I enter this in JIRA, since I'm
not sure of the terminology, maybe someone could let me know if it's a
known bug. My comments after the //

> db.testcoll.drop();

{"nIndexesWas" : 1 , "msg" : "all indexes deleted for collection" , "ns" : "mfs.testcoll" , "ok" : 1}

> db.testcoll.update({foo: {bar: 123}}, {"$inc": {"baz": 1}},

{upsert: true}

)
> db.testcoll.find()

{"_id" : ObjectId( "4ae725fd4666000000000f21") , "foo" :

{"bar" : 123}

, "baz" : 1}
// we upsert an object with a foo field matching exactly the value

{bar: 123}

and containing no other fields. It doesn't exist so we
create it and increment "baz".

> db.testcoll.update(

{"foo.bar": 123}

, {"$inc": {"baz": 1}},

{upsert: true}

)
> db.testcoll.find()

{"_id" : ObjectId( "4ae725fd4666000000000f21") , "foo" :

{"bar" : 123}

, "baz" : 2}
// we upsert an object with a foo field containing a bar field whose
value is 123. It exists already so "baz" is incremented.

> db.testcoll.drop()

{"nIndexesWas" : 1 , "msg" : "all indexes deleted for collection" , "ns" : "mfs.testcoll" , "ok" : 1}

> db.testcoll.update(

{"foo.bar": 123}

, {"$inc": {"baz": 1}},

{upsert: true}

)
> db.testcoll.find()

{"_id" : ObjectId( "4ae726234666000000000f22") , "foo.bar" : 123 , "baz" : 1}

// Again we upsert an object with a foo field containing a bar field
whose value is 123. It doesn't exist already. But this time the server
seems to misinterpret the query

{"foo.bar" : 123}

and creates a new
record with the field "foo.bar", rather than a new record with the
field "foo" containing a subfield "bar".



 Comments   
Comment by auto [ 16/Jan/10 ]

Author:

{'name': 'Eliot Horowitz', 'email': 'eliot@10gen.com'}

Message: fix upset with x.y query and $mod SERVER-390
http://github.com/mongodb/mongo/commit/d61342572459e7942871b427e373a686a04b55f7

Comment by Jon Stephens [ 13/Jan/10 ]

I get the same thing from the Perl driver on 1.2.1. See PERL-48. Didn't see this bug until now.

Comment by Eliot Horowitz (Inactive) [ 16/Dec/09 ]

split out case for $ queries

Comment by Ian White [ 03/Dec/09 ]

Here's another, somewhat related, problem with upserts – feel free to split but you might be able to kill these two birds with one stone:

> db.test.drop();
true
> db.test.update( { name: 'ian', fruits:

{ $ne: 'apple' }

}, { $push:

{ fruits: 'apple' }

},

{ upsert: true }

);
Cannot apply $push/$pushAll modifier to non-array

(I'm using the $ne conditional as a workaround for the lack of a $pushUnique / $pushAllUnique)

Anyway, the problem is that the first parameter is doing double duty as both criteria and the object to insert, so mongo thinks I mean to insert the literal subobject

{ $ne: 'apple' }

, and then run a $push on it, which isn't allowed. Jason is encountering a similar problem: the dot-notation he's using for criteria is not suitable for the inserted object.

I'm starting to think it might be best if upsert was different from update and was something like

upsert(criteria, insert, update)

This would fix Jason's problem, because he'd do:

db.testcol.upsert(

{ 'foo.bar': 123 }

, { foo:

{ bar: 123 }

, baz: 1 }, { $inc:

{ baz: 1 }

} );

And it would fix my problem, because I'd do (at least until we get $pushUnique):

db.test.upsert( { name: 'ian', fruits:

{ $ne: 'apple' }

},

{ name: 'ian', fruits: ['apple'] }

, { $push:

{ fruits: 'apple' }

} )

And it would resolve #453 as well.

Generated at Thu Feb 08 02:53:56 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.