¿Cuál es la manera más rápida para insertar un pandas DataFrame en mongodb con PyMongo?

Intentos

db.myCollection.insert(df.to_dict())

dio un error

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())

dio un error

TypeError: 'str' object does not support item assignment

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

dio un error

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)
  • ¿qué quieres hacer después? ¿quieres un doc por registro o un doc por dataframe?
  • Cada mongo registro tendrá los campos date, amount, price, y tid. tid debe ser un campo único
  • usted puede convertir el dataframe a un diccionario de la lista por: records = json.loads(df.to_json(orient='records')), el resultado será como:[{'c1': 1, 'c2': 1},{'c1': 2, 'c2': 2},{'c1': 3, 'c2': 3}], utilice sólo db.coll.insert_many(records). por cierto, uso df.to_dict('recoreds') puede contrarrestar Type error
InformationsquelleAutor Nyxynyx | 2013-11-23

7 Comentarios

  1. 26

    Dudo que haya un tanto más rápida y simple método. Si usted no se preocupe acerca de la conversión de datos, usted puede hacer

    >>> 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)

    Pero en caso de que intente carga de datos de la espalda, usted obtendrá:

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

    así que tendrás que convertir ‘a’ columnt de vuelta a datetimes, así como a todos no int, float o str campos en su DataFrame. Para este ejemplo:

    >>> df['A'] = pd.to_datetime(df['A'])
    >>> df
                               A
    0 2013-11-23 21:14:34.118531
    • db.myCollection.insert(records) debe ser reemplazado por el db.myCollection.insert_many(records) ver la advertencia //anaconda/bin/ipython:1: DeprecationWarning: insert is deprecated. Use insert_one or insert_many instead. #!/bin/bash //anaconda/bin/python.app
  2. 28

    Aquí tiene el camino más rápido. El uso de la insert_many método de pymongo 3 y ‘registros’ parámetro de to_dict método.

    db.insert_many(df.to_dict('records'))
    • Esta es la mejor idea de la omi, aunque no creo que la sintaxis se va a trabajar para el original de caso de uso. El problema básico es que mongo necesidades claves de cadena, mientras que su df tiene una marca de índice. Usted necesidad de utilizar los parámetros que se pasan a to_dict() para hacer las llaves en mongo ser algo distinto de fechas. Un uso frecuente de casos de los que he tenido es donde realmente se quiere cada fila en el df para ser un registro con un adicional de ‘fecha’ campo.
  3. 9

    odón puede hacerlo usando

    odo(df, db.myCollection)
    • Me gusta mucho odo, pero no terriblemente cuando el mongo uri no ha alfa nombre de usuario, password. Yo no lo recomiendo para nada, pero el uso de un no autenticado mongo.
    • Creo que odón de desarrollo se ha detenido o ha retrasado recientemente, a partir de 2019-ish.
  4. 3

    Si su dataframe tiene los datos que faltan (me.e Ninguno,nan) y no desea que los valores null clave en los documentos:

    db.insert_many(df.to_dict("records")) va a insertar claves con valores null. Si usted no desea que el vacío los valores de la clave en los documentos, puede utilizar una versión modificada de los pandas .to_dict("records") código de abajo:

    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)

    donde el if v != None and v == v he añadido comprobaciones para asegurarse de que el valor no es None o nan antes de ponerlo en la fila del diccionario. Ahora su .insert_many sólo se incluyen claves con valores en los documentos (y no null tipos de datos).

    • Esta es una buena manera, porque tratando con valores nulos es de hecho necesaria cuando la carga de dataframe a mongodb, y este método es más rápido que DataFrame.to_dict(), por CIERTO, columns = list(df.columns), entonces [{k: _maybe_box_datetimelike(v) for k, v in zip(columns, row) if v != None and v == v} for row in df.values] es incluso más rápido.
  5. 2

    Creo que hay buenas ideas en esta pregunta. En mi caso, he estado pasando el tiempo más teniendo cuidado de que el movimiento de grandes dataframes. En el caso de los pandas tiende a permitir la opción de chunksize (para los ejemplos en la los pandas.DataFrame.invoca to_sql). Así que creo que con contribuir aquí mediante la adición de la función que estoy utilizando en esta dirección.

    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
    • Esto es realmente útil, gracias. Puede que desee actualizar la Args (de Entrada) a la sección de entradas de corriente.
  6. 1

    cómo sobre esto:

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

    el id de una cadena única para que df

    • Gracias, me sale el error InvalidDocument: documents must have only string keys, key was <built-in function id>
    • tienes que generar el id por ti mismo
    • Es esta identificación de la misma como de costumbre _.id en mongo documentos? Si es así, parece un azar hash, ¿cómo se generan?
    • Falla por @Nyxynyx desde id es una novación de la función en Python, primordial no es recomendable. Se puede generar una simple prueba de identificación mediante el uso de id(df), pero dado que el IDENTIFICADOR de objeto no son persistentes a través de las sesiones, esto podría causar problemas dependiendo de cómo usted lo utiliza. Obras para la prueba, aunque.
    • Tengo maximum recursion level reached de error. Se fija con sys.setrecursionlimit(1000000)
  7. 1

    Acaba de hacer la cadena de claves!

    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)

Dejar respuesta

Please enter your comment!
Please enter your name here