2013-11-23 2 views
13

Каков самый быстрый способ вставки панда DataFrame в mongodb с помощью PyMongo?Вставьте Pandas Dataframe в mongodb с помощью PyMongo

Попытки

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

дал ошибку InvalidDocument: documents must have only string keys, key was Timestamp('2013-11-23 13:31:00', tz=None)

db.myCollection.insert(df.to_json()) 

дал ошибку TypeError: 'str' object does not support item assignment

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

дал ошибку InvalidDocument: documents must have only string keys, key was <built-in function id>

ДФ

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

Что вы хотите сделать после этого? вам нужен один документ на запись или один документ на каждый кадр? – alko

+0

Каждая запись монго будет иметь поля 'date',' amount', 'price' и tid. 'tid' должно быть уникальным полем – Nyxynyx

ответ

18

Я сомневаюсь, что это как быстрый и простой метод. Если вы не беспокоиться о преобразовании данных, вы можете сделать

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

Но в случае, если вы пытаетесь load data back, вы получите:

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

так что вам придется конвертировать «A» columnt обратно до datetime s, а также все не int, float или str полей в вашем DataFrame. В этом примере:

>>> df['A'] = pd.to_datetime(df['A']) 
>>> df 
          A 
0 2013-11-23 21:14:34.118531 
+2

'db.myCollection.insert (records)' следует заменить на 'db.myCollection.insert_many (записи)' см. Предупреждение '// anaconda/bin/ipython: 1: DeprecationWarning: insert устарел. Вместо этого используйте insert_one или insert_many. #!/Bin/bash // anaconda/bin/python.app' –

1

как об этом:

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

идентификатор будет уникальная строка для этого ФР

+0

Спасибо, я получаю сообщение об ошибке' InvalidDocument: документы должны иметь только строковые ключи, ключ был <встроенный идентификатор функции> ' – Nyxynyx

+0

, вы должны сгенерировать этот идентификатор самостоятельно – PasteBT

+0

Является ли этот идентификатор одинаковым как обычные '_.id' в документах монго? Если это так, это похоже на случайный хеш, как мне его создать? – Nyxynyx

10

Здесь у вас есть самый быстрый способ. Использование метода insert_many из pymongo 3 и параметра 'records' метода to_dict.

db.insert_many(df.to_dict('records')) 
+1

Это лучшая идея imo, хотя я не думаю, что синтаксис будет работать для исходного варианта использования. Основная проблема заключается в том, что mongo нужны строковые ключи, тогда как ваш df имеет индекс Timestamp. Вам нужно использовать параметры, переданные 'to_dict()', чтобы ключи в mongo были чем-то другим, кроме дат. Частый случай использования, который у меня был, - это то, где вы действительно хотите, чтобы каждая строка в df была записью с дополнительным полем «дата». –

7

odo может сделать это с помощью

odo(df, db.myCollection) 
+0

Мне очень нравится 'odo', но это терпит неудачу, когда монго-uri имеет не-альфа-имя пользователя, passwd. Я бы не рекомендовал его ни для чего, кроме использования неавторизованного монго. – armundle

1

Если dataframe имеет недостающие данные (т.е. None, нан), и вы не хотите, нулевые значения ключа в ваших документах:

db.insert_many(df.to_dict("records")) вставляет ключи с нулевыми значениями. Если вы не хотите, пустые ключевых значений в ваших документах, которые можно использовать модифицированную версию панд .to_dict("records") код ниже:

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) 

if v != None and v == v где я добавил проверку, чтобы убедиться, что значение не None или nan перед тем, как поместить его в словарь строки. Теперь ваш .insert_many будет включать только ключи со значениями в документах (и без типов данных null).

0

Я думаю, что в этом вопросе есть крутые идеи. В моем случае я тратил больше времени на заботу о движении больших кадров данных. В этом случае панды имеют тенденцию разрешать вам chunksize (примеры приведены в pandas.DataFrame.to_sql). Поэтому я думаю, что могу внести свой вклад, добавив функцию, которую я использую в этом направлении.

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 
Смежные вопросы