我创建了一个集合并添加了一个像这样的唯一键
db.user_services.createIndex({"uid":1 , "sid": 1},{unique:true,dropDups: true})
该集合看起来像这样 “user_services”
{
"_id" : ObjectId("55068b35f791c7f81000002d"),
"uid" : 15,
"sid" : 1,
"rate" : 5
},
{
"_id" : ObjectId("55068b35f791c7f81000002f"),
"uid" : 15,
"sid" : 1,
"rate" : 4
}
问题:
使用php驱动程序插入具有相同 uid和sid 的文档,然后插入。
我想要什么
答案 0 :(得分:34)
恭喜,您似乎找到了一个错误。这只发生在我的测试中的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 )
);
不允许任何更新操作“访问与”更新“文档部分中的另一个更新操作中使用的相同路径。
答案 1 :(得分:13)
我觉得当前最流行的答案对于这样一个基本的MongoDB操作来说有点过于局部和详细 - 通过密钥从mongo中删除重复项。
通过mongo的键删除重复项> 3.0很简单。只需运行此查询,替换yourDuplicateKey
并假设_id
是您的主键(请确保mongodump以防万一):
db.yourCollection.aggregate([
{ "$group": {
"_id": { "yourDuplicateKey": "$yourDuplicateKey" },
"dups": { "$push": "$_id" },
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$gt": 1 } }}
]).forEach(function(doc) {
doc.dups.shift();
db.yourCollection.remove({ "_id": {"$in": doc.dups }});
});
答案 2 :(得分:0)
另一种避免使用多个值重复记录的简单方法
示例: 使用以下代码,可以避免“学生姓名”和“父母姓名”字段的重复值
$DataForDB = array( "AdmissionNo" => $admissionNo,
"StudentName" => $StudentName, "ParentName" => $ParentName);
if(empty($Coll->findOne(array("StudenName" => $StudentName, "ParentName" => $ParentName)))){
$Coll->insertOne($DataForDB);
}
在这种情况下,我们将检查是否存在具有以下字段的文档(如果存在),如果不存在则不将数据输入到DB中。