我有一个备份服务数据库我正在编写to backup Yahoo! Groups。它会逐步检索具有连续数字ID的消息。存储在'message_id'
字段中。因此,如果服务上的最后一条消息是消息号10000,则备份完成后,数据库应包含10000个文档,每个文档的排序'message_id'
等同于range(1, 10000+1)
。
我想编写一个查询,产生缺少的消息ID。因此,如果我在数据库中有9995个文档,并且缺少消息10,15,49,99和1043,则应该返回[10, 15, 49, 99, 1043]
。
我已经完成了以下操作,只从数据库中获取ID并在我的应用代码中运行集合交集:
def missing_message_ids(self):
"""Return the set of the ids of all missing messages.."""
latest = self.get_latest_message()
ids = set(range(1, latest['_id']+1))
present_ids = set(doc['_id'] for doc in self.db.messages.find({}, {'_id': 1}))
return ids - present_ids
这对我的目的来说很好,但似乎对于大量的消息来说它可能会变得太慢。这更多是为了好奇而不是真正的性能要求:有没有更有效的方法来实现这一点,可能完全在数据库引擎上?
答案 0 :(得分:1)
在SQL word中,可以使用CTE,在mongo中我们可以使用$lookup
聚合作为一种CTE(公用表表达式)
拥有此数据结构
{
"_id" : ObjectId("575deea531dcfb59af388e17"),
"mesId" : 4.0
}, {
"_id" : ObjectId("575deea531dcfb59af388e18"),
"mesId" : 6.0
}
缺少"mesId" : 5.0
我们可以使用此聚合查询,该查询将投影所有下一个预期的ID,并加入它们。这里的限制是,如果我们按顺序丢失了多条消息,但可以通过预测下一个Id并再次进行$ lookup来扩展。
var project = {
$project : {
_id : 0,
mesId : 1,
nextId : {
$sum : ["$mesId", 1]
}
}
}
var lookup = {
$lookup : {
from : "claudiu",
localField : "nextId",
foreignField : "mesId",
as : "missing"
}
}
var match = {
$match : {
missing : []
}
}
db.claudiu.aggregate([project, lookup, match])
并输出:
{
"mesId" : 4.0,
"nextId" : 5.0,
"missing" : []
}