Quel est le moyen le plus rapide d’insérer un DataFrame pandas dans mongodb en utilisant PyMongo
?
Tentatives
db.myCollection.insert(df.to_dict())
a donné une erreur
InvalidDocument: documents must have only string keys, the key was Timestamp('2013-11-23 13:31:00', tz=None)
db.myCollection.insert(df.to_json())
a donné une erreur
TypeError: 'str' object does not support item assignment
db.myCollection.insert({id: df.to_json()})
a donné une erreur
InvalidDocument: documents must have only string a keys, key was <built-in function id>
df
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 150 entries, 2013-11-23 13:31:26 to 2013-11-23 13:24:07
Data columns (total 3 columns):
amount 150 non-null values
price 150 non-null values
tid 150 non-null values
dtypes: float64(2), int64(1)
Je doute qu'il existe une méthode à la fois quickest et simple. Si vous ne vous souciez pas de la conversion des données, vous pouvez le faire.
>>> import json
>>> df = pd.DataFrame.from_dict({'A': {1: datetime.datetime.now()}})
>>> df
A
1 2013-11-23 21:14:34.118531
>>> records = json.loads(df.T.to_json()).values()
>>> db.myCollection.insert(records)
Mais si vous essayez de charger les données , vous obtiendrez:
>>> df = read_mongo(db, 'myCollection')
>>> df
A
0 1385241274118531000
>>> df.dtypes
A int64
dtype: object
vous devrez donc reconvertir la colonne 'A' en datetime
s, ainsi que tous les champs non int
, float
ou str
de votre DataFrame
. Pour cet exemple:
>>> df['A'] = pd.to_datetime(df['A'])
>>> df
A
0 2013-11-23 21:14:34.118531
Ici vous avez le moyen le plus rapide. Utilisation de la méthode insert_many
de pymongo 3 et du paramètre 'records' de to_dict
method .
db.insert_many(df.to_dict('records'))
odo peut le faire en utilisant
odo(df, db.myCollection)
Si votre cadre de données a des données manquantes (c'est-à-dire Aucune, nan) et que vous ne souhaitez pas que les valeurs de clé null soient dans vos documents:
db.insert_many(df.to_dict("records"))
insérera des clés avec des valeurs NULL. Si vous ne voulez pas que les valeurs de clé vides dans vos documents, vous pouvez utiliser une version modifiée du code pandas .to_dict("records")
ci-dessous:
from pandas.core.common import _maybe_box_datetimelike
my_list = [dict((k, _maybe_box_datetimelike(v)) for k, v in Zip(df.columns, row) if v != None and v == v) for row in df.values]
db.insert_many(my_list)
où le if v != None and v == v
j'ai ajouté vérifie que la valeur n'est pas None
ou nan
avant de la placer dans le dictionnaire de la ligne. Désormais, votre .insert_many
n'inclura que les clés avec des valeurs dans les documents (et aucun type de données null
).
Je pense qu'il y a des idées cool dans cette question. Dans mon cas, je passe plus de temps à m'occuper du déplacement de grandes trames de données. Dans ces cas, les pandas ont tendance à vous permettre de choisir chunksize (par exemple, dans le pandas.DataFrame.to_sql ). Donc, je pense que je peux contribuer ici en ajoutant la fonction que j'utilise dans cette direction.
def write_df_to_mongoDB( my_df,\
database_name = 'mydatabasename' ,\
collection_name = 'mycollectionname',
server = 'localhost',\
mongodb_port = 27017,\
chunk_size = 100):
#"""
#This function take a list and create a collection in MongoDB (you should
#provide the database name, collection, port to connect to the remoete database,
#server of the remote database, local port to tunnel to the other machine)
#
#---------------------------------------------------------------------------
#Parameters / Input
# my_list: the list to send to MongoDB
# database_name: database name
#
# collection_name: collection name (to create)
# server: the server of where the MongoDB database is hosted
# Example: server = '132.434.63.86'
# this_machine_port: local machine port.
# For example: this_machine_port = '27017'
# remote_port: the port where the database is operating
# For example: remote_port = '27017'
# chunk_size: The number of items of the list that will be send at the
# some time to the database. Default is 100.
#
#Output
# When finished will print "Done"
#----------------------------------------------------------------------------
#FUTURE modifications.
#1. Write to SQL
#2. Write to csv
#----------------------------------------------------------------------------
#30/11/2017: Rafael Valero-Fernandez. Documentation
#"""
#To connect
# import os
# import pandas as pd
# import pymongo
# from pymongo import MongoClient
client = MongoClient('localhost',int(mongodb_port))
db = client[database_name]
collection = db[collection_name]
# To write
collection.delete_many({}) # Destroy the collection
#aux_df=aux_df.drop_duplicates(subset=None, keep='last') # To avoid repetitions
my_list = my_df.to_dict('records')
l = len(my_list)
ran = range(l)
steps=ran[chunk_size::chunk_size]
steps.extend([l])
# Inser chunks of the dataframe
i = 0
for j in steps:
print j
collection.insert_many(my_list[i:j]) # fill de collection
i = j
print('Done')
return
que dis-tu de ça:
db.myCollection.insert({id: df.to_json()})
id sera une chaîne unique pour ce df
Il suffit de faire des clés de chaîne!
import json
dfData = json.dumps(df.to_dict('records'))
savaData = {'_id': 'a8e42ed79f9dae1cefe8781760231ec0', 'df': dfData}
res = client.insert_one(savaData)
##### load dfData
data = client.find_one({'_id': 'a8e42ed79f9dae1cefe8781760231ec0'}).get('df')
dfData = json.loads(data)
df = pd.DataFrame.from_dict(dfData)