我有一个带字符串格式数组的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的新手。
提前致谢。
答案 0 :(得分:0)
如上所述,主要问题是JSON"喜欢" "字符串中的数据"因为criteria
缺少键周围的引号。正确使用引号,您可以将字符串解析为一个列表,数据的结构如何。
您实际上可以在现有列表上运行map
和re.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会更有用。