Insérer une Dataframe Pandas dans mongodb en utilisant PyMongo

Quelle est la manière la plus rapide d'insérer une 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, 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 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)
21
demandé sur Nyxynyx 2013-11-24 00:01:32

6 réponses

je doute qu'il y ait à la fois la plus rapide et la méthode simple . Si vous ne vous souciez pas de la conversion des données, vous pouvez 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 dans le cas où vous essayez de charger des données en arrière , vous obtiendrez:

>>> df = read_mongo(db, 'myCollection')
>>> df
                     A
0  1385241274118531000
>>> df.dtypes
A    int64
dtype: object

donc vous devrez convertir 'A' colonne retour à datetime s, ainsi que tous pas int , float ou str champs dans votre DataFrame . Pour cet exemple:

>>> df['A'] = pd.to_datetime(df['A'])
>>> df
                           A
0 2013-11-23 21:14:34.118531
22
répondu alko 2017-05-23 12:25:42

ici vous avez le moyen le plus rapide. En utilisant la méthode insert_many de pymongo 3 et la méthode" records "de to_dict .

db.insert_many(df.to_dict('records'))
12
répondu dieguico 2018-08-10 08:30:04

odo peut le faire à l'aide de

odo(df, db.myCollection)
8
répondu Femto Trader 2015-12-27 17:37:44

si votre base de données contient des données manquantes (I. e None, nan) et vous ne voulez pas de valeurs clés nulles dans vos documents:

db.insert_many(df.to_dict("records")) insérera des touches avec des valeurs nulles. Si vous ne voulez pas les valeurs clés vides dans vos documents, vous pouvez utiliser une version modifiée de pandas .to_dict("records") code 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é des contrôles pour s'assurer que la valeur n'est pas None ou nan avant de le mettre dans la ligne du dictionnaire. Maintenant, votre .insert_many n'inclura que des clés avec des valeurs dans les documents (et pas de types de données null ).

2
répondu Radical Edward 2016-06-15 00:00:49

je pense qu'il y a des idées cool dans cette question. Dans mon cas, j'ai passé plus de temps à prendre soin du mouvement des grandes images de données. Dans ce cas pandas tend à vous permettre l'option de chunksize (pour des exemples dans les pandas .DataFrame.to_sql ). Je pense donc apporter ma contribution 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
2
répondu Rafael Valero 2018-03-06 09:48:37

que pensez-vous de ceci:

db.myCollection.insert({id: df.to_json()})

id sera une chaîne unique pour que df

1
répondu PasteBT 2013-11-23 20:20:38