将嵌套的MongoDB导入到Pandas

时间:2018-08-05 21:56:43

标签: python json mongodb pandas

我在MongoDB中有一个带有大量嵌套文档的Collection,我想展平并导入到Pandas。有一些嵌套的dict,但是还有我要转换成列的dict列表(有关详细信息,请参见下面的示例)。

我已经有功能,可用于较小批次的文档。但是解决方案(我发现它是in the answer to this question)使用json。 json.loads操作的问题在于,对于集合中的较大选择,它失败并显示MemoryError

我尝试了许多建议使用其他json解析器(例如ijson)的解决方案,但是由于不同的原因,它们都没有解决我的问题。如果我想通过json保持转换,剩下的唯一方法是将较大的选择分块到较小的文档组中并重复进行解析。

在这一点上,我认为-这是我的主要问题-也许有一种更聪明的方法来进行嵌套,而无需在MongoDB或Pandas中以某种方式直接通过json绕道而行?

这是文档的简化示例:

{
  '_id': ObjectId('5b40fcc4affb061b8871cbc5'),
  'eventId': 2,
  'sId' : 6833,
  'stage': {
    'value': 1,
    'Name': 'FirstStage'
  },
  'quality': [
    {
      'type': {
        'value': 2,
        'Name': 'Color'
      },
      'value': '124'
    },
    {
      'type': {
        'value': 7,
        'Name': 'Length'
      },
      'value': 'Short'
    },
    {
      'type': {
        'value': 15,
        'Name': 'Printed'
      }
    }
}

这是成功的数据帧表示的样子(出于可读性,我跳过了列“ _id”和“ sId”:

    eventId    stage.value    stage.name    q_color    q_length    q_printed
1   2          1              'FirstStage'  124        'Short'     1 

到目前为止,我的代码(遇到内存问题-参见上文):

def load_events(filter = 'sId', id = 6833, all = False):
  if all:
    print('Loading all events.')
    cursor = events.find()
  else:
    print('Loading events with %s equal to %s.' %(filter, id))
    print('Filtering...')
    cursor = events.find({filter : id})

  print('Loading...')
  l = list(cursor)

  print('Parsing json...')
  sanitized = json.loads(json_util.dumps(l))

  print('Parsing quality...')
  for ev in sanitized:
    for q in ev['quality']:
        name = 'q_' + str(q['type']['Name'])
        value = q.pop('value', 1)
        ev[name] = value
    ev.pop('quality',None)

  normalized = json_normalize(sanitized)

  df = pd.DataFrame(normalized)

  return df

1 个答案:

答案 0 :(得分:1)

您不需要使用json解析器转换嵌套结构。只需从记录列表中创建数据框:

./file

然后使用大熊猫来解压缩列表和字典:

df = DataFrame(list(cursor))

我使用三个步骤来解压缩嵌套的数据类型。首先,使用名称和值创建对(元组)的平面列表。在第二步中,基于元组的字典从元组的第一个位置获取键,并从第二个位置获取值。然后,使用集合一次提取所有现有的属性名称。每个属性都使用循环获得一个新列。在循环内部,每对的值都映射到相应的列单元格。