Как уже отмечалось, основная проблема заключается в том, что 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)
Присвоение регулярному выражению для добавления двойных кавычек вокруг ключей в 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 при вставке в коллекцию, и это намного полезнее, чем строка.
И снова "лично" я бы не использовал "именованные ключи" внутри списка для 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 будут намного полезнее, если путь будет более последовательным.