纯粹从聚合框架的角度来看,有几种方法可以实现这个。
您可以在现代版本中直接应用$setUnion
:
db.collection.aggregate([
{ "$project": {
"foo_list": { "$setUnion": [ "$foo_list", "$foo_list" ] }
}}
])
或者更传统地使用$unwind
和$addToSet
:
db.collection.aggregate([
{ "$unwind": "$foo_list" },
{ "$group": {
"_id": "$_id",
"foo_list": { "$addToSet": "$foo_list" }
}}
])
如果你只对重复项感兴趣,那么可以通过一般分组来实现:
db.collection.aggregate([
{ "$unwind": "$foo_list" },
{ "$group": {
"_id": {
"_id": "$_id",
"foo_list": "$foo_list"
},
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$ne": 1 } } },
{ "$group": {
"_id": "$_id._id",
"foo_list": { "$push": "$_id.foo_list" }
}}
])
如果你确实想用另一个更新语句从数据中“删除”重复项,那么最后一种形式可能对你有用,因为它可以识别出重复的元素。
因此,在最后一种形式中,从样本数据返回的结果标识了重复项:
{
"_id" : ObjectId("53f5f7314ffa9b02cf01c076"),
"foo_list" : [
{
"id" : "98aa4987-d812-4aba-ac20-92d1079f87b2",
"name" : "Foo 1",
"slug" : "foo-1"
}
]
}
当从包含重复条目的数组中返回每个文档的集合结果时,将返回哪些条目是重复的。这是您需要更新的信息,您需要循环结果以指定来自结果的更新信息,以删除重复项。
实际上,每个文档需要使用两个更新语句来完成此操作,因为简单的$pull
操作会移除“两个”项目,而这不是您想要的:
var cursor = db.collection.aggregate([
{ "$unwind": "$foo_list" },
{ "$group": {
"_id": {
"_id": "$_id",
"foo_list": "$foo_list"
},
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$ne": 1 } } },
{ "$group": {
"_id": "$_id._id",
"foo_list": { "$push": "$_id.foo_list" }
}}
])
var batch = db.collection.initializeOrderedBulkOp();
var count = 0;
cursor.forEach(function(doc) {
doc.foo_list.forEach(function(dup) {
batch.find({ "_id": doc._id, "foo_list": { "$elemMatch": dup } }).updateOne({
"$unset": { "foo_list.$": "" }
});
batch.find({ "_id": doc._id }).updateOne({
"$pull": { "foo_list": null }
});
});
count++;
if ( count % 500 == 0 ) {
batch.execute();
batch = db.collection.initializeOrderedBulkOp();
}
});
if ( count % 500 != 0 ) {
batch.execute();
}
这是现代 MongoDB 2.6 及以上版本处理方式:使用聚合的游标结果和批量操作进行更新。但原则仍然相同:
识别文档中的重复项
循环处理结果,对受影响的文档进行更新
使用$unset
和位置占位符 $
设置“第一个”匹配的数组元素为null
使用$pull
来移除数组中的null
条目
因此,经过上述操作处理后,样本现在看起来像这样:
{
"_id" : ObjectId("53f5f7314ffa9b02cf01c076"),
"foo_list" : [
{
"id" : "98aa4987-d812-4aba-ac20-92d1079f87b2",
"name" : "Foo 1",
"slug" : "foo-1"
},
{
"id" : "157569ec-abab-4bfb-b732-55e9c8f4a57d",
"name" : "Foo 3",
"slug" : "foo-3"
}
]
}
使用“duplicated”项目仍然完整的方式删除重复项。这是您从集合中识别和删除重复数据的处理方式。