我需要为每个用户收集一个集合中的最新文档(这里是通知),然后删除另一个。让我们假设我有这样的数据:
[
{ user: 1, time: ISODate("Mon, 14 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 1, time: ISODate("Tue, 15 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 1, time: ISODate("Fri, 23 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Tue, 27 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Wed, 28 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Wed, 28 Sep 2015 07:33:16 +0000"), msg: "message" }
]
例如,我想获取最后2个通知并删除其他通知,因此user 1
的结果应为:
[
{ user: 1, time: ISODate("Tue, 15 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 1, time: ISODate("Fri, 23 Sep 2015 06:22:36 +0000"), msg: "message" }
]
数据将是这样的:
[
{ user: 1, time: ISODate("Tue, 15 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 1, time: ISODate("Fri, 23 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Tue, 27 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Wed, 28 Sep 2015 06:22:36 +0000"), msg: "message" },
{ user: 2, time: ISODate("Wed, 28 Sep 2015 07:33:16 +0000"), msg: "message" }
]
和其他属于user 1
的记录将被删除。
那么有效的方法是什么?
答案 0 :(得分:1)
使用以下内容查找最后两个
db.collection.find({user:1}).sort({time:-1}).limit(2)
使用以下内容删除除最后两个文档之外的所有文档
var i = 0;
var user_ids = [];
db.users.find({user:1},{_id:1}).sort({time:-1}).forEach(function(user) {
if(i>1)
user_ids[i] = user._id;
i++;
});
db.users.remove({_id: {$in: user_ids}})
除了最后两个之外,没有直接method
删除所有document
。
但是,如果您一次只想删除一个document
,那么您可以通过定义删除属性并将其设置为findAndModify
来使用true
函数
答案 1 :(得分:1)
我认为你的文件是这样的:
{ "_id" : ObjectId("562b38f9d6995d3311d9ddce"), "user" : 1, "time" : ISODate("2015-09-14T06:22:36Z"), "msg" : "message" }
{ "_id" : ObjectId("562b38f9d6995d3311d9ddcf"), "user" : 1, "time" : ISODate("2015-09-15T06:22:36Z"), "msg" : "message" }
{ "_id" : ObjectId("562b38f9d6995d3311d9ddd2"), "user" : 2, "time" : ISODate("2015-09-28T06:22:36Z"), "msg" : "message" }
{ "_id" : ObjectId("562b38f9d6995d3311d9ddd3"), "user" : 2, "time" : ISODate("2015-09-28T07:33:16Z"), "msg" : "message" }
从MongoDB 3.2,您可以使用$slice
运算符为每个用户仅获取最后两个文档
var bulkOp = db.collection.initializeOrderedBulkOp();
var count = 0;
db.collection.aggregate([
{ "$sort": { "user": 1, "time": -1 }},
{ "$group": { "_id": "$user", "times": { "$push": "$time" } }},
{ "$project": {
"times": {
"$slice": [ "$times", 2 ]
}
}}
]).forEach(function(doc) {
bulkOp.find({
"user": doc._id,
"time": { "$nin": doc.times }
}).remove();
count++;
if(count % 100 === 0) {
//Execute per 100 operations and re-init
bulkOp.execute();
bulkOp = db.collection.initializeOrderedBulkOp();
}
})
// Clean up queues
if(count > 0) {
bulkOp.execute();
}
在MongoDB 3.2之前,您需要user
$group
您的文档,然后使用返回times
数组的$push
运算符。从那时起,您需要使用.forEach
循环遍历聚合结果,然后在sort
顺序中首先reverse
times
数组返回最后两次并使用.slice
方法。然后,您可以使用"bulk"操作删除文档,以获得最高效率。当然,$nin
运算符可以过滤掉旧文档。
var bulkOp = db.collection.initializeOrderedBulkOp();
var count = 0;
db.collection.aggregate([
{ "$group": {
"_id": "$user",
"times": { "$push": "$time" }
} }
]).forEach(function(doc) {
var times = doc.times.sort(function(t1, t2) {
return t1 < t2 ? -1 : (t1 > t2 ? 1 : 0);
}).reverse().slice(-2);
bulkOp.find({
"user": doc._id,
"time": { "$nin": times }
}).remove();
count++;
if(count % 100 === 0) {
//Execute per 100 operations and re-init
bulkOp.execute();
bulkOp = db.collection.initializeOrderedBulkOp();
}
})
// Clean up queues
if(count > 0) {
bulkOp.execute();
}