Вставить массив из CSV, используя Pymongo - PullRequest
0 голосов
/ 16 мая 2018

У меня есть CSV-файл с массивом в строковом формате, как показано ниже:

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

Я использую Python с пандами и 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 formatter, но после вставки в 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 голосов
/ 16 мая 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...