2016-10-25 3 views
1

파이썬 스크립트를 사용하여 csv로 내보내기 할 때 문제가 있습니다. 일부 배열 데이터는 Mongodb에서 CSV로 내 보내야하지만 세 개의 하위 필드 데이터가 열에 덤프되기 때문에 다음 스크립트가 제대로 내보내지지 않았습니다. 답변 필드 아래에 세 개의 필드 (순서, 텍스트, answerid)를 CSV의 세 가지 다른 열로 구분하고 싶습니다.파이썬을 사용하여 mongodb에서 csv로 데이터 내보내기

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 작성자가 아니라 Mongo에서만 이해합니다.)

내가해야하는 것으로 알고있는 것은 답변 목록을 "걸어 다니고"그 목록에있는 각 레코드 (각 사전) 중 하나의 사전을 만드는 것입니다. 복수형의 사용에 대한

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 : 당신이 의 목록을 일단 당신이 그 전달하고 csv 파일에 쓸 수 사전 "평평". 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 

편집 :

귀하의 쿼리 questions 컬렉션의 모든 항목을 반환합니다 (cursor = db.questions.find ({},{'_id':1, 'answers.order':1, 'answers.text':1, 'answers.answerId':1})을 만드는 것). 이 컬렉션이 매우 큰 경우 cursoriterator으로 사용할 수 있습니다.

이미 알게 되겠지만 위 코드에서 첫 번째 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에서 4 개의 분리 된 필드가 있습니다. 정말 고마워. – user7070824

+0

다행히 도울 수있었습니다! 그런데 내 대답이 당신의 문제를 해결했다면 왼쪽의 큰 체크 박스를 클릭하여 대답으로 받아 들여야합니다 (SO 네티켓 : http://meta.stackexchange.com/questions/14994/do-you-feel- dirty-if-you-you-nudge-new-users-to-they-indica) – BorrajaX

+0

누구든지 스크립트를 사용하려면 1 단계와 2 단계 사이에 공백을 넣어야합니다. 그것은 완벽하게 작동합니다. 당신의 도움을 주셔서 감사합니다. – user7070824

관련 문제