使用pymongo从csv插入数组

时间:2018-05-16 05:47:59

标签: python-3.x mongodb pandas numpy

我有一个带字符串格式数组的csv文件,如下所示:

date,name,criteria
2018-05-16,John,"[{'age':35},{'birthyear':1983}]"
2018-05-16,Jane,"[{'age':36},{'birthyear':1982}]"

我正在使用Python与pandas和numpy来处理这个

我需要以下列格式将此文件导入MongoDB集合:

{
   "date":'2018-05-16',
   "name":"John",
   "criteria" : [
         {"age":35},
         {"birthyear" : 1983}
   ]
},
{
   "date":'2018-05-16',
   "name":"Jane",
   "criteria" : [
         {"age":36},
         {"birthyear" : 1982}
   ]
 }

`

我尝试使用json格式化程序,但在插入Mongodb后,我得到的数组与csv文件中的相同。

我尝试了以下方法:

#Approach 1
import pymongo
from pymongo import MongoClient
import pandas as pd
import numpy as np
import json
from datetime import datetime

df = pd.read_csv("file.csv")
records = json.loads(df.T.to_json()).values()
db.tmp_collection.insert_many(data.to_dict('record'))



#Approach 2
import pymongo
from pymongo import MongoClient
import pandas as pd
import numpy as np
import json
from datetime import datetime

df = pd.read_csv("file.csv")
data_json = json.loads(df.to_json(orient='records'))
db.tmp_collection.insert_many(data_json)

两者都在Mongodb集合中提供以下输出:

{
"date" : "2018-05-16",
"name" : "John",
"criteria" : "[{age:35},{birthyear:1983}]"
}

你能提出一些更好的方法吗? 附:我是Python的新手。

提前致谢。

1 个答案:

答案 0 :(得分:0)

如上所述,主要问题是JSON"喜欢" "字符串中的数据"因为criteria缺少键周围的引号。正确使用引号,您可以将字符串解析为一个列表,数据的结构如何。

您实际上可以在现有列表上运行mapre.sub(),并将criteria替换为已解析的版本。

根据您声明的表格中的源数据:

date,name,criteria
2018-05-16,John,"[{age:35},{birthyear:1983}]"
2018-05-16,Jane,"[{age:36},{birthyear:1982}]"

然后重要的部分是:

df = pd.read_csv("file.csv")
records = json.loads(df.to_json(orient='records'))

pattern = r"({|,)(?:\s*)(?:')?([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)(?:')?(?:\s*):"

records = map(lambda x:
  dict(x.items() +
    {
      'criteria': json.loads(
        re.sub(pattern, "\\1\"\\2\":", x['criteria'])
      )
    }.items()
  ),
  records
)

这基本上是通过前面列出的每个项目并在"字符串"上进行替换。引用对象中的键。然后当然将现在有效的JSON字符串解析为字典对象列表。

这会产生如下数据:

[{u'criteria': [{u'age': 35}, {u'birthyear': 1983}],
  u'date': u'2018-05-16',
  u'name': u'John'},
 {u'criteria': [{u'age': 36}, {u'birthyear': 1982}],
  u'date': u'2018-05-16',
  u'name': u'Jane'}]

然后您可以将其传递到insert_many()以在集合中创建保留所需格式的文档。

db.tmp_collection.insert_many(records)

归因于此处使用的正则表达式模式的regular expression to add double quotes around keys in javascript

我个人会更进一步,至少解析datetime

records = map(lambda x:
  dict(x.items() +
    {
      'date': datetime.strptime(x['date'], '%Y-%m-%d'),
      'criteria': json.loads(
        re.sub(pattern, "\\1\"\\2\":", x['criteria'])
      )
    }.items()
  ),
  records
)

MongoDB在插入集合时会使用BSON Date,这比字符串更有用。

再次,"个人"我不会使用"命名键"在MongoDB的列表中。相反,我宁愿"重新映射"更像"k""v"这样的标准,如:

records = map(lambda x:
  dict(x.items() +
    {
      'date': datetime.strptime(x['date'], '%Y-%m-%d'),
      'criteria':
      [i for s in map(lambda y: [{ 'k': k, 'v': v } for k,v, in y.iteritems()] , json.loads(
        re.sub(pattern, "\\1\"\\2\":", x['criteria'])
      )) for i in s]
    }.items()
  ),
  records
)

其结构如下:

[{u'criteria': [{'k': u'age', 'v': 35}, {'k': u'birthyear', 'v': 1983}],
  u'date': datetime.datetime(2018, 5, 16, 0, 0),
  u'name': u'John'},
 {u'criteria': [{'k': u'age', 'v': 36}, {'k': u'birthyear', 'v': 1982}],
  u'date': datetime.datetime(2018, 5, 16, 0, 0),
  u'name': u'Jane'}]

主要原因是"查询"如果路径更加一致,那么使用MongoDB会更有用。