一日一技:在 MongoDB 中,如何批量更新不同數據為不同值?
我們知道,當使用 Pymongo 更新MongoDB 字段的時候,我們有兩種常見的方法:
- handler.update_one({'name': 'value'}, {'$set': {'aa': 'bb'}})
- handler.update_many({'name': 'value'}, {'$set': {'aa': 'bb'}})
其中,update_one是更新第一條滿足查詢條件的數據;update_many是更新所有滿足查詢條件的數據。大家在使用update_many的時候,不知道有沒有想過一個問題:update_many會對所有滿足條件的文檔更新相同的字段。例如,對于上面第二行代碼,所有name字段為value的數據,在更新以后,新的數據的aa字段的值全都是bb。那么,有沒有辦法一次性把不同的字段更新成不同的數據呢?
例如,我們的 MongoDB 中有如下數據:
sid | name | sex | result | is_qualified |
---|---|---|---|---|
1 | 王曉一 | 男 | 80 | true |
2 | 張小二 | 女 | 69 | false |
3 | 劉小三 | 男 | 76 | false |
4 | 朱小四 | 女 | 75 | true |
5 | 馬小五 | 男 | 50 | false |
6 | 趙小六 | 女 | 77 | true |
7 | 錢小七 | 男 | 60 | false |
8 | 孫小八 | 女 | 68 | false |
9 | 李小九 | 男 | 98 | true |
10 | 周小十 | 女 | 61 | false |
假設這是一份成績表,一開始,要求男生不低于80分,女生不低于70分,is_qualified字段才會為True。后來改了計分規則,變成男生不低于90分,女生不低于60分,is_qualified就能為 True,否則為 False。所以現在需要批量更新數據。顯然,對男生而言,有一些原本為True的需要變成 False;對女生而言,有一些原本為 False 的,要變成 True。如果讓你直接使用update_many,你可能需要寫成兩條更新語句:
- handler.update_many({'sex': '男', 'result': {'$lt': 90}}, {'$set': {'is_qualified': False}})
- handler.update_many({'sex': '女', 'result': {'$gte': 60}}, {'$set': {'is_qualified': True}})
那有沒有辦法只發一次請求,就同時更新兩組數據呢?其實方法也是有的,就是bulk_write:
- import pymongo
- handler = pymongo.MongoClient().test_db.test_col
- handler.bulk_write([
- pymongo.UpdateMany({'sex': '男', 'result': {'$lt': 90}}, {'$set': {'is_qualified': False}}),
- pymongo.UpdateMany({'sex': '女', 'result': {'$gte': 60}}, {'$set': {'is_qualified': True}})
- ])
bulk_write接收一個列表作為參數。這個列表里面的每一個元素是一個pymongo.X對象,這里的 X 可能是InsertOne/InsertMany/DeleteOne/DeleteMany/UpdateOne/ UpdateMany……,基本上就是你想使用的對應操作的駝峰命名法形式。
這種方式,Pymongo 會在一次請求同時提交這兩組操作,減少網絡連接的時間消耗。
批量操作不僅支持UpdateOne,還支持各種其他操作,你可以閱讀Bulk Write Operations — PyMongo 3.11.4 documentation[1]。
參考資料
[1]Bulk Write Operations — PyMongo 3.11.4 documentation: https://pymongo.readthedocs.io/en/stable/examples/bulk.html