【问题标题】:mongoengine bulk upsert a batch of record?mongoengine bulk upsert 一批记录?
【发布时间】:2015-10-28 10:20:30
【问题描述】:

我想upsert(update or insert) a list of record,其实我知道mongodb从mongodb3.0开始就支持bulk操作。

我想知道mongoenginemongoengine (0.10.0)中是否支持bulk upsert operation

如果没有,我想知道upsert的记录列表,我知道mongoengine支持insert这样的批处理:

class User(Document):
    username = StringField(required=True)
    password = StringFiedl(required=True)
    meta = {'db_alias': 'user_info', 'collection': 'user', 
             'indexes': [{'fields': ['username'], 'unique': True}]
           }

def save_users(self, users):
    Users.objects.insert(users) # raise mongoengine.errors.NotUniqueError

【问题讨论】:

  • @AndreL 实际上最后一个是我的代码
  • @AndreL 也许简单的模式让你理解我,我有一个唯一的键username,我只想插入用户或如果用户存在则更新用户。

标签: python mongodb mongoengine upsert


【解决方案1】:

您实际上可以通过从 MongoEngine 使用的 pymongo 驱动程序访问底层集合对象来直接使用bulk operations API。 MongoDB 本身从 2.6 版本开始就支持批量操作。自 pymongo 驱动程序 v3 以来,有更新的方法可以访问这些,但基本方法自从相应的驱动程序更新到 2.6 服务器版本(pymongo 2.7)后就已经存在。

要使用 MongoEngine 获得此功能,您可以从您的类中调用未记录的 ._get_collection() 以返回 collection 对象:

bulk = Users._get_collection().initialize_ordered_bulk_op()

for user in users:  # where users is a list of dicts containing data to work on
    bulk.find({ "matchField": user['matchField'] }).upsert().replace_one(user)

bulk.execute()

或您可能想要的bulk methods 的任何其他用法,例如.update_one()。而.upsert() 是修改此类更新语句的链式方法。

您在这里使用的是原始 python 对象,因为 MongoEngine 本身没有直接的等价物。但是您可以通过访问底层驱动程序中的方法来使用这些操作

【讨论】:

  • 'Collection' 对象不可调用。如果您打算在“Collection”对象上调用“inititalize_ordered_bulk_op”方法,则会失败,因为不存在这样的方法。
  • @roger 哎呀。错字!应该是initialize_ordered_bulk_op()
  • @非常感谢,我的笨蛋!我找到了解决raw python objects问题的方法,Mongoengine Document有一个方法to_mongo()转换为dict,bulk.find({ "matchField": user['matchField'] }).upsert().replace_one(user.to_mongo())
  • @roger 我并没有将其视为一个问题,因为对于大多数人来说,在他们实例化到一个类之前数据可能是一个原始对象,是的,我已经知道to_mongo() .我的意思基本上是说,在“批量”情况下,由于您绕过 MongoEngine 包装器进行存储,绕过将数据实例化到类的开销似乎是合乎逻辑的,无论如何,现在您知道了一个未记录的方法和通过 pymongo 使用批量 API 方法。
【解决方案2】:

你可以使用mongo.collection.Collection.bulk_write:

operations = [
    pymongo.ReplaceOne({'username': user. username}, user.to_mongo(), upsert=True)
    for user in users
]
result = User._get_collection().bulk_write(operations)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 2015-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    相关资源
    最近更新 更多