就我个人而言,我会利用 ObjectId 值本身是“单调的”或因此“值不断增加”的事实,这意味着“最年轻的”或“最近的”将出现在自然排序列表的末尾.
因此,与其强制聚合管道进行排序,最合乎逻辑和最有效的做法是在处理每个响应时对每个文档返回的唯一 _id 值列表进行排序。
所以基本上是使用您必须找到的列表:
Remove Duplicates from MongoDB
实际上是我的答案(也是你本周第二个参考的人,但没有收到有用的投票!嗯!),它只是一个简单的.sort() 应用在光标内返回数组的迭代:
使用 _id 值
var bulk = db.History.initializeOrderedBulkOp(),
count = 0;
// List "all" fields that make a document "unique" in the `_id`
// I am only listing some for example purposes to follow
db.History.aggregate([
{ "$group": {
"_id": "$sessionId",
"ids": { "$push": "$_id" }, // _id values are already unique, so $addToSet adds nothing
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$gt": 1 } } }
],{ "allowDiskUse": true}).forEach(function(doc) {
doc.ids.sort().reverse(); // <-- this is the only real change
doc.ids.shift(); // remove first match, which is now youngest
bulk.find({ "_id": { "$in": doc.ids } }).remove(); // removes all $in list
count++;
// Execute 1 in 1000 and re-init
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.History.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
使用特定字段
如果您“真的”设置为添加另一个日期值以确定哪个是最年轻的,那么只需首先添加到$push 中的数组,然后应用客户端排序功能。同样只是一个非常简单的更改:
var bulk = db.History.initializeOrderedBulkOp(),
count = 0;
// List "all" fields that make a document "unique" in the `_id`
// I am only listing some for example purposes to follow
db.History.aggregate([
{ "$group": {
"_id": "$sessionId",
"ids": { "$push": {
"_id": "$_id",
"created": "$timeCreated"
}},
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$gt": 1 } } }
],{ "allowDiskUse": true}).forEach(function(doc) {
doc.ids = doc.ids.sort(function(a,b) { // sort dates and just return _id
return a.created.valueOf() < a.created.valueOf()
}).map(function(el) { return el._id });
doc.ids.shift(); // remove first match, which is now youngest
bulk.find({ "_id": { "$in": doc.ids } }).remove(); // removes all $in list
count++;
// Execute 1 in 1000 and re-init
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.History.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
所以这是一个非常简单的过程,不会对用于识别重复项的原始过程进行“真正的”更改,然后删除除一个之外的所有重复项。
这里最好的方法总是让服务器完成查找重复项的工作,然后在客户端迭代游标时,您可以从返回的数组中计算出要保留的文档以及要保留的文档删除。