恭喜,您似乎发现了一个错误。这仅在我的测试中发生在 MongoDB 3.0.0 中,或者至少在 MongoDB 2.6.6 中不存在。错误现在记录在SERVER-17599
注意:
实际上不是“问题”,而是“按设计”确认。删除了版本 3.0.0 的选项。不过仍然在documentation 中列出。
问题在于,当您尝试在“复合键”字段上存在重复项的集合上创建该索引时,未创建索引并且出错。在上面,索引创建应该在 shell 中产生:
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"errmsg" : "exception: E11000 duplicate key error dup key: { : 15.0, : 1.0 }",
"code" : 11000,
"ok" : 0
}
当不存在重复项时,您可以按照当前尝试创建索引,它将被创建。
所以要解决这个问题,首先使用以下过程删除重复项:
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})
然后将不再插入包含重复数据的进一步插入,并记录相应的错误。
最后要注意的是,“dropDups”是/不是删除重复数据的非常优雅的解决方案。如上所示,您确实想要具有更多控制权的东西。
对于第二部分,不要使用.insert(),而是使用.update() 方法。它有一个"upsert" 选项
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array( '$set' => $someData ),
array( 'upsert' => true )
);
因此,“找到”的文档被“修改”,未找到的文档被“插入”。另请参阅$setOnInsert,了解仅在实际插入文档而不是在修改文档时创建某些数据的方法。
对于您的具体尝试,.update() 的正确语法是三个参数。 “查询”、“更新”和“选项”:
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array(
'$set' => array( "field" => "this" ),
'$inc' => array( "counter" => 1 ),
'$setOnInsert' => array( "newField" => "another" )
),
array( "upsert" => true )
);
不允许任何更新操作“访问与该“更新”文档部分中另一个更新操作中使用的路径相同的路径。