2016-10-25 3 views
1

У меня возникли проблемы с экспортом в csv с помощью скрипта python. некоторые данные массива должны быть экспортированы в CSV из Mongodb, но следующий сценарий не экспортировался должным образом, потому что три подполя данных сбрасываются в столбец. Я хочу разделить три поля (порядок, текст, ответ) в поле ответов на три разных столбца в CSV.экспортировать данные в csv из mongodb с помощью python

образец MongoDB:

"answers": [ 
     { 
      "order": 0, 
      "text": { 
       "en": "Yes" 
      }, 
      "answerId": "527d65de7563dd0fb98fa28c" 
     }, 
     { 
      "order": 1, 
      "text": { 
       "en": "No" 
      }, 
      "answerId": "527d65de7563dd0fb98fa28b" 
     } 
    ] 

сценарий питона:

import csv 
cursor = db.questions.find ({},{'_id':1, 'answers.order':1, 'answers.text':1, 'answers.answerId':1}) 
cursor = list(cursor) 
with open('answer_2.csv', 'w') as outfile: 

    fields = ['_id','answers.order', 'answers.text', 'answers.answerid'] 
    write = csv.DictWriter(outfile, fieldnames=fields) 
    write.writeheader() 
    for x in cursor: 
     for y, v in x.iteritems(): 
      if y == 'answers' 
       print (y, v) 
       write.writerow(v) 
       write.writerow(x) 
+0

Не могли бы вы изменить свой вопрос, чтобы показать правильно отформатированный код? Кроме того, это поможет, если вы добавите пример того, как выглядят данные, которые вы получаете от Mongo. – BorrajaX

+0

, пожалуйста, помогите мне. – user7070824

ответ

3

Итак ... Проблема заключается в том, что csv писатель не понимает понятие "subdictionaries", как Монго возвращает его.

Если я правильно понял, то при запросе Монго, Вы получаете словарь, как это:

{ 
    "_id": "a hex ID that correspond with the record that contains several answers", 
    "answers": [ ... a list with a bunch of dicts in it... ] 
} 

Так что, когда csv.DictWriter пытается писать, что это только писать один словарь (самый верхний). Он не знает (или не заботится) о том, что answers - это список, содержащий словари, значения которых также должны быть записаны в столбцах (доступ к полям в словарях с использованием точечной нотации, такой как answers.order, понимается только Монго, а не автором csv)

Насколько я понимаю, вы должны сделать так, чтобы «пройти» список ответов и создать один словарь из каждой записи (каждого словаря) в этом списке. Если у вас есть список «сплющенные» словарей, которые вы можете передавать их и записать их в файл csv:

cursor = client.stack_overflow.stack_039.find(
    {}, {'_id': 1, 'answers.order': 1, 'answers.text': 1, 'answers.answerId': 1}) 

# Step 1: Create the list of dictionaries (one dictionary per entry in the `answers` list) 
flattened_records = [] 
for answers_record in cursor: 
    answers_record_id = answers_record['_id'] 
    for answer_record in answers_record['answers']: 
     flattened_record = { 
      '_id': answers_record_id, 
      'answers.order': answer_record['order'], 
      'answers.text': answer_record['text'], 
      'answers.answerId': answer_record['answerId'] 
     } 
     flattened_records.append(flattened_record) 

# Step 2: Iterate through the list of flattened records and write them to the csv file 
with open('stack_039.csv', 'w') as outfile: 
    fields = ['_id', 'answers.order', 'answers.text', 'answers.answerId'] 
    write = csv.DictWriter(outfile, fieldnames=fields) 
    write.writeheader() 
    for flattened_record in flattened_records: 
     write.writerow(flattened_record) 

Whatch для использования существительных. answers_record отличается answer_record

Это создает файл, как это:

$ cat ./stack_039.csv 
_id,answers.order,answers.text,answers.answerId 
580f9aa82de54705a2520833,0,{u'en': u'Yes'},527d65de7563dd0fb98fa28c 
580f9aa82de54705a2520833,1,{u'en': u'No'},527d65de7563dd0fb98fa28b 

EDIT:

Ваш запрос (тот, который делает cursor = db.questions.find ({},{'_id':1, 'answers.order':1, 'answers.text':1, 'answers.answerId':1})) вернет все записи в questions коллекции. Если эта коллекция очень большая, вы можете использовать cursor как iterator.

Как вы, возможно, уже поняли, первый цикл for в моем коде выше помещает все записи в список (список flattened_records). Вы можете выполнять ленивую загрузку, итерации через cursor (вместо того, чтобы загружать все элементы в памяти, извлекать их, делать с ними что-то, получать следующее, что-то делать с ним ...).

Это немного медленнее, но больше памяти.

cursor = client.stack_overflow.stack_039.find(
    {}, {'_id': 1, 'answers.order': 1, 'answers.text': 1, 'answers.answerId': 1}) 

with open('stack_039.csv', 'w') as outfile: 
    fields = ['_id', 'answers.order', 'answers.text', 'answers.answerId'] 
    write = csv.DictWriter(outfile, fieldnames=fields) 
    write.writeheader() 
    for answers_record in cursor: # Here we are using 'cursor' as an iterator 
     answers_record_id = answers_record['_id'] 
     for answer_record in answers_record['answers']: 
      flattened_record = { 
       '_id': answers_record_id, 
       'answers.order': answer_record['order'], 
       'answers.text': answer_record['text'], 
       'answers.answerId': answer_record['answerId'] 
      } 
      write.writerow(flattened_record) 

Он будет производить тот же .csv файл, как показано выше.

+0

это сработало. это превосходно! После запуска скрипта я получил четыре разделенных поля в csv. большое спасибо. – user7070824

+0

Рад, что я смог помочь! Кстати, если мой ответ решает вашу проблему, не стесняйтесь щелкнуть большой флажок слева от него, чтобы принять его как ответ (SO netiquette: http://meta.stackexchange.com/questions/14994/do-you-feel- dirty-if-you-nudge-new-users-to-accept-your-answer-when-they-indicat) – BorrajaX

+0

Если кто-то хочет использовать скрипт, обязательно поставьте пробел между шагами 1 и 2. Он работает отлично. Спасибо за вашу помощь. – user7070824

Смежные вопросы