Табулирование глубоко вложенной коллекции MongoDB с использованием PyMongo - PullRequest
0 голосов
/ 24 апреля 2019

Я запрашиваю коллекцию, используя 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 голосов
/ 25 апреля 2019

Решение

Первая проблема с моей логикой заключалась в том, что 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
...