这是我的文档的一个示例:
[{name:"duplicate", value:true, id:2910921},{name:"duplicate", value:true, id:32838293},{name:"duplicate", value:false, id:3283232},{name:"notDuplicate", value:true, id:382932}]
如果有多个包含相同名称和相同值的文档,我想删除。在上面的示例中,它将删除一个文档,即{name:"duplicate", value:true, id:2910921}
或{name:"duplicate", value:true, id:32838293}
,对我来说哪一个都没有关系。
到目前为止,我已经考虑只为每个字段创建一个新字段,就像newField:“ duplicatetrue”,然后我可以在其中使用distinct来删除重复项,但是我在弄清楚如何将具有不同类型的两个不同字段合并为一个新字段。我当然也愿意接受更好的建议。这是我到目前为止的内容:
db.collection(collectionName).updateMany({}, {$set: {"newField": ["$name","$value"] }})
但是,上面的行不输出值,而是输出完全为newField的值:[“ $ name”,“ $ value”]
从$ name和$ value中删除引号也不起作用。
我正在使用Node mongodb驱动程序:3.5.8
您可以通过两种方式完成
$out
具有破坏性,并且在生产环境中收集数百万个文档可能是一个问题,那么您可以首先读取所有_id
的文档以删除并使用.deleteMany()一次删除所有文档。 (您可以在文档上使用任何唯一标识符而不是_id
,但我默认使用_id
作为它的索引-这可以帮助更快地运行deleteMany()
。)>步骤1:
使用$out
-正如我说过的那样,它具有破坏性,因为如果输入名称匹配,它将覆盖整个集合,或者将通过聚合查询的结果创建一个新集合。因此,在使用$out
作为最后阶段之前,请很好地测试您的聚合查询。在一切都足够好之后,还可以将数据写入临时集合并重命名集合。重命名集合时请考虑停机时间
查询:
mongoplaygrounddb.collection.aggregate([ { $group: { _id: { name: "$name", value: "$value" }, doc: { $last: "$$ROOT" } // Retrieve only last doc in a group } }, { $replaceRoot: { newRoot: "$doc" } // replace doc as object as new root of document }, { $out : 'collection_new' } // Test above aggregation & then use this ])
Test:
步骤2:
_ids
列表。查询:
mongoplaygrounddb.collection.aggregate([ /** * Group on matching docs : * { name: "duplicate", value: false}, * { name: "duplicate", value: true}, * { name: "duplicate-yes", value: true}, * { name: "notDuplicate", value: true} * */ { $group: { _id: { name: "$name", value: "$value" }, _idsNeedsToBeDeleted: { $push: "$$ROOT._id" } // push all `_id`'s to an array } }, /** Remove first element - which is removing a doc */ { $project: { _id: 0, _idsNeedsToBeDeleted: { $slice: [ "$_idsNeedsToBeDeleted", 1, { $size: "$_idsNeedsToBeDeleted" } ] } } }, { $unwind: "$_idsNeedsToBeDeleted" // Unwind `_idsNeedsToBeDeleted` }, /** Group without a condition & push all `_idsNeedsToBeDeleted` fields to an array */ { $group: { _id: "", _idsNeedsToBeDeleted: { $push: "$_idsNeedsToBeDeleted" } } }, {$project : { _id : 0 }} // Optional stage /** At the end you'll have an [{ _idsNeedsToBeDeleted: [_ids] }] or [] */ ])
Test:
.deleteMany()
-删除所有文档:查询:
db.collection.deleteMany( { "_id" : {$in : [_ids]} } );
在
.deleteMany()
之前的考虑,您需要检查聚合结果不是一个空数组[]
,并且有一个文档,其中_idsNeedsToBeDeleted
字段是一个数组。另外,由于我们要与数据库中的_id
相匹配-聚合_idsNeedsToBeDeleted
数组将是一个字符串数组-因此遍历该数组,将字符串转换为ObjectId()
并在删除查询中使用该ObjectId()
数组。
注意:
无论您选择哪个步骤-由于我们都在name + value
上分组,因此您需要确保所有文档都包含这些字段。
我不确定mongo,但是您可以使用该节点删除重复项。我尝试这种方法的要求之一,可以正常工作。请在需要var名称时通过尝试尝试此操作。
在节点中本地执行似乎很有效(可能不是最快或最有效的方法,但以下方法可行:]