php - MongoDB Duplicate Documents even after adding unique key -
i have created collection , added unique key
db.user_services.createindex({"uid":1 , "sid": 1},{unique:true,dropdups: true})
the collection looks "user_services"
{ "_id" : objectid("55068b35f791c7f81000002d"), "uid" : 15, "sid" : 1, "rate" : 5 }, { "_id" : objectid("55068b35f791c7f81000002f"), "uid" : 15, "sid" : 1, "rate" : 4 }
problem :
am using php driver insert documents same uid , sid , getting inserted.
what want
- on mongo shell : add unique key on uid , sid no duplicate documents same uid , sid.
- on php side : having mysql "insert (value) on duplicate key update rate=rate+1". whenever try insert document, should inserted if not there else should update rate field of document
congratulations, appear have found bug. happens mongodb 3.0.0 in testing, or @ least not present @ mongodb 2.6.6. bug recorded @ server-17599
note: not "issue" confirmed "by design". dropped option version 3.0.0. still listed in documentation though.
the problem index not being created , errors when attempt create on collection existing duplicates on "compound key" fields. on above, index creation should yield in shell:
{ "createdcollectionautomatically" : false, "numindexesbefore" : 1, "errmsg" : "exception: e11000 duplicate key error dup key: { : 15.0, : 1.0 }", "code" : 11000, "ok" : 0 }
when there no duplicates present can create index trying , created.
so work around this, first remove duplicates procedure this:
db.events.aggregate([ { "$group": { "_id": { "uid": "$uid", "sid": "$sid" }, "dups": { "$push": "$_id" }, "count": { "$sum": 1 } }}, { "$match": { "count": { "$gt": 1 } }} ]).foreach(function(doc) { doc.dups.shift(); db.events.remove({ "_id": {"$in": doc.dups }}); }); db.events.createindex({"uid":1 , "sid": 1},{unique:true})
then further inserts containing duplicate data not inserted , appropriate error recorded.
the final note here "dropdups" is/was not elegant solution removing duplicate data. want more control demonstrated above.
for second part, rather use .insert()
use .update()
method. has "upsert" option
$collection->update( array( "uid" => 1, "sid" => 1 ), array( '$set' => $somedata ), array( 'upsert' => true ) );
so "found" documents "modified" , documents not found "inserted". see $setoninsert
way create data when document inserted , not when modified.
for specific attempt, correct syntax of .update()
3 arguments. "query", "update" , "options":
$collection->update( array( "uid" => 1, "sid" => 1 ), array( '$set' => array( "field" => "this" ), '$inc' => array( "counter" => 1 ), '$setoninsert' => array( "newfield" => "another" ) ), array( "upsert" => true ) );
none of update operations allowed "access same path" used in update operation in "update" document section.
Comments
Post a Comment