【原创】Python Mongo 批量操作

向数据库新增大量数据是经常性的需求, pymongo 支持 insert_many.

但主键是我们自己外部定义生成的, 并且实现更新记录, 就有点困难.

注: MongoDB 主键字段是_id

# insert_many 用法
insert_many(documents, ordered=True, bypass_document_validation=False)

Insert an iterable ofdocuments.

>>> db.test.count()
0
>>> result = db.test.insert_many([{'x': i} for i in range(2)])
>>> result.inserted_ids
[ObjectId('54f113fffba522406c9cc20e'), ObjectId('54f113fffba522406c9cc20f')]
>>> db.test.count()
2

insert_many(docs, ordered=True) # 遇到错误 break, 并且抛出异常
insert_many(docs, ordered=False) # 遇到错误 continue, 循环结束后抛出异常
# 无论 ordered 是 True 或者 False, 批量添加的时候遇到重复的, 并不会对历史数据更新

insert_one(document, bypass_document_validation=False)
replace_one(filter, replacement, upsert=False, bypass_document_validation=False, collation=None)
update_one(filter, update, upsert=False, bypass_document_validation=False, collation=None)
update_many(filter, update, upsert=False, bypass_document_validation=False, collation=None)
#  都无法实现批量插入, 没有插入\有则更新的需求.

解决办法 1

有一个$setOnInsert的方式.但目的是为了仅仅插入不纯在的数据.
<<ahref="https://stackoverflow.com/questions/31375606/is-there-a-way-to-skip-over-existing-ids-for-insert-many-in-pymongo-3-0">Isthere a way to skip over existing _id’s for insert_many in Pymongo3.0?>

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=True)
for doc in docs:
    bulk.find({ "_id": doc["_id"] }).upsert().updateOne({
        "$setOnInsert": doc
    })

response = bulk.execute()

# 这并不能实现主键存在的情况下对数据进行更新.

### 正确姿势如下
def insert_many(collection, docs=None, update=True):
    if not docs:
        return
    # $set 的时候, 会更新数据, setOnInsert只插入不更新
    update_key = "$set" if update else "$setOnInsert"
    bulk = BulkOperationBuilder(collection, ordered=False)
    for i in docs:
        if i["_id"]:
            bulk.find({"_id":i["_id"]}).upsert().update_one({update_key:i })
        else:
            bulk.insert(i)
    result = bulk.execute()
    modify_count = result.get("nModified")
    insert_count = result.get("nUpserted") + result.get("nInserted")

# 如上, 实现了主键已存在时, 对数据进行更新. 主键不在表中的时候对数据进行插入操作. 并且, 如果要插入的数据没有设置主键 _id, 进行普通的插入操作即可.

解决方法 2

Send a batch of write operations to the server.

from pymongo import UpdateOne, ReplaceOne # InsertOne, DeleteOne
>>> from pymongo import MongoClient as MC
>>> db = MC().test.test1

>>> db.count()
1

>>> list(db.find())
[{u'_id': u'a', u'n': u'a'}]

#  先用 UpdateOne 测试一下
>>> db.bulk_write([UpdateOne({"_id":"a"},{"$set":{"n":"aa"}}, upsert=True), UpdateOne({"_id":"b"},{"$set":{"n":"b"}}, upsert=True)])
0x102d4d370>
>>> list(db.find())
[{u'_id': u'a', u'n': u'aa'}, {u'_id': u'b', u'n': u'b'}]
# 可以看到 记录 a 的 "n" 成功被更新为 "aa", 并且新增了一条记录 b
# 再用 ReplaceOne 测试一下
>>> db.bulk_write([ReplaceOne({"_id":"b"},{"n":"bb"}, upsert=True), ReplaceOne({"_id":"c"},{"n":"cc"}, upsert=True)])
0x102d4d370>
>>> list(db.find())
[{u'_id': u'a', u'n': u'aa'}, {u'_id': u'b', u'n': u'bb'}, {u'_id': u'c', u'n': u'cc'}]

# 可以看到, 记录 b 的 n 从 "b" 更新为 "bb", 并且新增了一条记录 c
# 这里需要注意的是, 如果使用 ReplaceOne, update 的值不能使用"$set"
# 注意区分 ReplaceOne 和 UpdateOne 的区别. 加上$set后是更新操作. 没有$set 是覆盖操作.


END.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值