[SERVER-1640] $in operator for behaves unexpected on upserts Created: 19/Aug/10  Updated: 07/Mar/14  Resolved: 19/Aug/10

Status: Closed
Project: Core Server
Component/s: Write Ops
Affects Version/s: 1.6.1
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Torsten Curdt Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

any


Operating System: ALL
Participants:

 Description   

We would like to reduce the number of updates by using the $in operator going from

buckets = [ '2010', '2010-08', '2010-08-01' ]
buckets.each do |bucket|
@totals.update(

{ 'bucket' => bucket }

, { '$inc' => { 'downloads' => 1 }}, :upsert => true)
end

to

buckets = [ '2010', '2010-08', '2010-08-01' ]
@totals.update({ 'bucket' =>

{ "$in" => buckets }

}, { '$inc' => { 'downloads' => 1 }}, :upsert => true)

Unfortunately we get very strange and inconsistent results.

db.test.find()
db.test.update(

{"b": 2}

, { "$inc":

{ "d": 1 }

}, true)
db.test.find()

{ "_id" : ObjectId("4c6d1e345153667a3fd349b8"), "b" : 2, "d" : 1 }

db.test.update(

{"b": 3}

, { "$inc":

{ "d": 1 }

}, true)
db.test.find()

{ "_id" : ObjectId("4c6d1e345153667a3fd349b8"), "b" : 2, "d" : 1 } { "_id" : ObjectId("4c6d1e485153667a3fd349b9"), "b" : 3, "d" : 1 }

db.test.update({"b":

{ "$in": [ 2, 3, 4 ] }

}, { "$inc":

{ "d": 1 }

}, true)
db.test.find()

{ "_id" : ObjectId("4c6d1e345153667a3fd349b8"), "b" : 2, "d" : 2 } { "_id" : ObjectId("4c6d1e485153667a3fd349b9"), "b" : 3, "d" : 1 }

We would expect also

{ "_id" : ObjectId("4c6d1e485153667a3fd349ba"), "b" : 4, "d" : 1 }

to be there. Then we found there is 'multi' option to turn on in (from http://www.mongodb.org/display/DOCS/Updating )

"multi - if all documents matching criteria should be updated"

But that still does not create a documents as expected.

db.test.update({"b":

{ "$in": [ 2, 3, 4 ] }

}, { "$inc":

{ "d": 1 }

}, true, true)
db.test.find()

{ "_id" : ObjectId("4c6d1e345153667a3fd349b8"), "b" : 2, "d" : 3 } { "_id" : ObjectId("4c6d1e485153667a3fd349b9"), "b" : 3, "d" : 2 }

Now even more weird. Trying again it does create a document - but not the one expected:

db.test.update({"b":

{ "$in": [ 55, 66 ] }

}, { "$inc":

{ "d": 1 }

}, true, true)
db.test.find()

{ "_id" : ObjectId("4c6d1e345153667a3fd349b8"), "b" : 2, "d" : 3 } { "_id" : ObjectId("4c6d1e485153667a3fd349b9"), "b" : 3, "d" : 2 } { "_id" : ObjectId("4c6d1f1a5153667a3fd349ba"), "d" : 1 }

What are we missing here?



 Comments   
Comment by Eliot Horowitz (Inactive) [ 19/Aug/10 ]

In the last piece, it is supposed to do an upsert because the query doesn't match anything.

Comment by Eliot Horowitz (Inactive) [ 19/Aug/10 ]

You can't combine a multi-update and an upsert.

You can do a query with $in and figure out which objects need to inserted, and then do an multi-update on the others.

But i think you're better of jusing doing multiple upserts in your code

Comment by Torsten Curdt [ 19/Aug/10 ]

...and why is it creating

{ "_id" : ObjectId("4c6d1f1a5153667a3fd349ba"), "d" : 1 }

then? according to you that should not happen either.

Comment by Torsten Curdt [ 19/Aug/10 ]

Got at better way to combine the multiple updates in one then?

Comment by Eliot Horowitz (Inactive) [ 19/Aug/10 ]

If you use upsert with multi, if any docs match, nothing will be created.

Think about the case where you say update( { x :

{ $gt : 5 }

} )
we wouldn't want to create a value for every possible value of x

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