(随意重命名问题)
我在mongo集合中有一些类似于:
的数据{
...
'tree_id': 'ABC123',
'serial_id': 'XYZ789',
...
}
从json请求中,我最终获得了大量的serial_id值(称为wantedIDs
)。我需要创建一个类似于:
{'tree_id_1': [...all the serial_ids that matched tree_id_1...],
'tree_id_2': [...all the serial_ids that matched tree_id_2...],
...}
我可以做类似的事情:
myMap = defaultdict(list)
for doc in client.database.collection.find({'serial_id': {'$in': wantedIDs}}):
myMap[doc['tree_id']].append(doc['serial_id'])
我想知道是否有更多的pythonic或mongorific方式这样做?我是一个非常新手的pymongo用户。我也很好奇$in
不是要走的路,如果有的话。 wantedIDs
的列表可能非常大。
答案 0 :(得分:0)
我想知道是否有更多的pythonic或mongorific方式这样做?
是的,有。寻找MongoDB Aggregation Framework。 Pymongo集合有一种aggregate
方法用于您尝试执行的操作(请参阅更新)。
我也很好奇,如果有的话,$ in是不可行的。
好吧,我不完全确定$in
,但我认为您可以将数据放入其中,直到达到BSON文档大小限制为16兆字节。无论如何,我建议不要接近这个限制,因为它可能会减慢你的应用程序和MongoDB服务器的速度。
<强>更新强>
聚合无法解决潜在的大$in
问题。 find
使用的相同查询将进入聚合管道的$match
运算符,因此适用相同的限制。
如果您检测到serial_id
的列表太大,或者因为它会达到BSON限制,或者因为它会导致wantedIDs
,那么您可以做的一件事就是根本不按$in
进行过滤MongoDB几乎扫描整个集合。
您还可以在MongoDB中执行单个聚合,并将树ID的整个映射带到应用程序中,然后在Python代码中进行匹配。该聚合的结果也不能超过BSON最大文档大小。如果集合变化不大,您可能会尝试缓存聚合结果以提高性能。
当然,所有这些都可能是过早的优化。在不知道收集/应用的细节的情况下,很难说清楚。
除此之外,如果不重新考虑应用程序或重组数据以完全避免{{1}},您就无法做到更多。
答案 1 :(得分:0)
聚合框架可以让你关闭:
>>> db.collection.insert({'tree_id': 'ABC123', 'serial_id': 1})
ObjectId('52b105e3ca1ce9bb42202f63')
>>> db.collection.insert({'tree_id': 'ABC123', 'serial_id': 2})
ObjectId('52b105e4ca1ce9bb42202f64')
>>> db.collection.insert({'tree_id': '2', 'serial_id': 1})
ObjectId('52b105f8ca1ce9bb42202f65')
>>> db.collection.aggregate([{
'$group': {
'_id': '$tree_id',
'serial_ids': {'$push': '$serial_id'}
}
}])
{u'ok': 1.0,
u'result': [{u'_id': u'2', u'serial_ids': [1]},
{u'_id': u'ABC123', u'serial_ids': [1, 2]}
]
}
从这里开始,用Python完成:
dict([(row['_id'], row['serial_ids']) for row in result['result']])