使用PyMongo汇总深层嵌套的MongoDB集合

时间:2019-04-24 17:27:38

标签: python mongodb pandas pymongo

我正在使用 pymongo 查询集合:

import pymongo

client = pymongo.MongoClient('0.0.0.0', 27017)
db = client.documents
collection = db.collections
test_data = collection.find_one({'metadata.encodingStage.terms.data.line.data.account.shortDescription': {'$exists': True}}, 
{'metadata.encodingStage.terms.data.line.data.account.shortDescription': 1})

我在这里使用find_one进行说明,但实际上,这是整个集合中的find查询。

这将提供以下输出:

{'_id': ObjectId('5a2fb9371de46756df51f37b'),
 'metadata': {'encodingStage': {'terms': {'data':
    {'line': [{'data': {'account': {'shortDescription': ['123456']}}},
              {'data': {'account': {'shortDescription': ['7890123']}}}]}}}}}

但是,我想要表格格式的数据,如SQL或Pandas所述:

                               _id    shortDescription
-------------------------------------------------------
ObjectId('5a2fb9371de46756df51f37b')            123456
ObjectId('5a2fb9371de46756df51f37b')           7890123

我了解如何在Python中执行此操作,并遍历结果,但是为了提高计算效率,我希望更多列表可以在Mongo中进行。

有没有一种简单的方法可以使用pymongo将结果作为{'_id': 'XXX', 'shortDescription': 'XXX')对进行输出,并且可以有效地制表?

要取消聚合吗?

我尝试通过$unwind聚合的方式进行此操作:

unwind = collection.aggregate([{'$unwind': '$metadata.encodingStage.terms.data.line.data.account.shortDescription'}])

...但是不会返回任何数据。

1 个答案:

答案 0 :(得分:0)

解决方案

我的逻辑的第一个问题是line是一个数组,因此需要先展开。

将其与两个$project步骤以及叶数组上的最后一个$unwind相结合,将数据扁平化,以提供(_id, shortDescription)对,可以快速将其转换为熊猫DataFrame:

db.collection.aggregate([
                           {"$project": {"line": "$metadata.encodingStage.terms.data.line"}},
                           {"$unwind": "$line"},
                           {"$project": {"shortDescription": "$line.data.account.shortDescription"}},
                           {"$unwind": "$shortDescription"}
                        ])

输出:

[{'_id': ObjectId('xxxxxxxxxxxxxxx123'), 'shortDescription': '12340000'},
 {'_id': ObjectId('xxxxxxxxxxxxxxx123'), 'shortDescription': '43210000'},
 {'_id': ObjectId('yyyyyyyyyyyyyyy789'), 'shortDescription': '56780000'},
 {'_id': ObjectId('yyyyyyyyyyyyyyy789'), 'shortDescription': '78920000'},
 {'_id': ObjectId('yyyyyyyyyyyyyyy789'), 'shortDescription': '55550000'}]

可以将其加载到熊猫中,而无需进行其他转换:

import pandas as pd
results = db.collection.aggregate([
                           {"$project": {"line": "$metadata.encodingStage.terms.data.line"}},
                           {"$unwind": "$line"},
                           {"$project": {"shortDescription": "$line.data.account.shortDescription"}},
                           {"$unwind": "$shortDescription"}
                        ])
df = pd.DataFrame([item for item in results])

输出:

print(df)

                  _id shortDescription
0  xxxxxxxxxxxxxxx123         12340000
1  xxxxxxxxxxxxxxx123         43210000
2  yyyyyyyyyyyyyyy789         56780000
3  yyyyyyyyyyyyyyy789         78920000
4  yyyyyyyyyyyyyyy789         55550000