LoginSignup
16
13

More than 3 years have passed since last update.

Pythonでmongodbを操作する~その3:update編~

Last updated at Posted at 2019-08-09

当記事の記載範囲

この記事ではPythonでmongodbに接続してから、update(SQLで言ってもupdate)の使い方について記載します。
内容としては以下になります。
1. update_one
2. update_many
3. replace_one
4. find_one_and_update
5. find_one_and_replace

mongodbの起動やpymongoのインストール方法については以下の記事をご覧いただければ幸いです。
https://qiita.com/bc_yuuuuuki/items/2b92598434f6cc320112

準備データ

mongodbの準備データは以下のとおりです。

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
> show collections
employee
log
salary
> db.salary.find()
{ "_id" : ObjectId("5d4acf84de925ae437e2c123"), "name" : "山田", "salary" : 300000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c124"), "name" : "佐藤", "salary" : 400000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000 }
{ "_id" : ObjectId("5d4b81a4de925ae437e2c126"), "name" : "山田", "salary" : 500000 }

Pythonでupdateを使ってみる

まずはupdate_oneから使ってみます。
これから紹介する内容は基本的には同じ内容になっています。
第一引数のfileterに更新条件を設定し、第二引数のupdateやreplaceに更新する内容を設定します。

update_oneの使い方

MongoUpdateSample.py
from pymongo import MongoClient

class MongoUpdateSample(object):

    def __init__(self, dbName, collectionName):
        self.client = MongoClient()
        self.db = self.client[dbName]
        self.collection = self.db.get_collection(collectionName)

    def find(self, projection=None,filter=None, sort=None):
        return self.collection.find(projection=projection,filter=filter,sort=sort)

    def update_one(self, filter, update):
        return self.collection.update_one(filter,update)

    def update_many(self, filter, update):
        return self.collection.update_many(filter,update)

    def replace_one(self, filter, replacement):
        return self.collection.replace_one(filter, replacement)

    def find_one_and_replace(self, filter, replacement):
        return self.collection.find_one_and_replace(filter, replacement)

mongo = MongoUpdateSample('test', 'salary')
find = mongo.find()
for doc in find:
    print(doc)

update = mongo.update_one({'name':'山田'},{'$set':{'salary':600000}})
print('更新件数:' + str(update.matched_count))
find = mongo.find()
for doc in find:
    print(doc)

やっている内容としては更新前のデータを表示し、nameフィールドが'山田'の給料を600000に更新する。
更新完了後に更新件数と更新後のデータを表示するというものです。

実行結果

--------------------更新前--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 300000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000.0}
更新件数:1
--------------------更新後--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 600000}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000.0}

はい。今回使ったのはupdate_oneなので'name'フィールドが'山田'となっているデータ2件のうち、1件が更新されています。
正直、今のところあまり利用場面が思い浮かんでいません。。
気になるのは'salary'フィールドの値ですね。
今回用意したデータはmongodbのコンソールから登録を行いました。
その際、'salary'フィールドには整数で値を設定しているのですが、pymongoのfindでデータを取得するとfloatになっていることが分かります。
また、pymongoのupdate_oneで更新した整数の値は、findで取得するとint型になっています。
このあたり、キャストなど注意する必要がありそうです。
ちなみに更新後のデータをmongodbのコンソールで確認すると全て整数で表示されています。

> db.salary.find()
{ "_id" : ObjectId("5d4acf84de925ae437e2c123"), "name" : "山田", "salary" : 600000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c124"), "name" : "佐藤", "salary" : 400000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000 }
{ "_id" : ObjectId("5d4b81a4de925ae437e2c126"), "name" : "山田", "salary" : 500000 }

update_manyの使い方

update_manyの使い方はほとんどupdate_oneと同じです。
update_oneを呼び出している部分をupdate_manyに変更し、更新するパラメーターも変更しました。

(抜粋)MongoUpdateSample.py
mongo = MongoUpdateSample('test', 'salary')
find = mongo.find()
print('--------------------更新前--------------------')
for doc in find:
    print(doc)

update = mongo.update_many({'name':'山田'},{'$set':{'salary':7777777}})
print('更新件数:' + str(update.matched_count))
find = mongo.find()
print('--------------------更新後--------------------')
for doc in find:
    print(doc)

実行結果

--------------------更新前--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 600000}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000.0}
更新件数:2
--------------------更新後--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 7777777}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 7777777}

'name'フィールドが'山田'と一致する全てのデータの'salary'が更新されました。

replace_oneの使い方

これはドキュメント(RDBで言うところのレコード)を丸々入れ替えるという内容になります。
mongodbにより一意に採番される「_id(主キー)」以外のフィールドを新しいフィールドに入れ替えることができます。
SQLには無い構文ですね。早速やってみましょう。

(抜粋)MongoUpdateSample.py
mongo = MongoUpdateSample('test', 'salary')
find = mongo.find()
print('--------------------更新前--------------------')
for doc in find:
    print(doc)

update = mongo.replace_one({'name':'山田'},{'fullname':'山田 太郎','rank':5,'profession':'Engineer','position':'Manager'})
print('更新件数:' + str(update.matched_count))
find = mongo.find()
print('--------------------更新後--------------------')
for doc in find:
    print(doc)

実行結果

--------------------更新前--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 7777777}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 7777777}
更新件数:1
--------------------更新後--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'fullname': '山田\u3000太郎', 'rank': 5, 'profession': 'Engineer', 'position': 'Manager'}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 7777777}

全角スペースが文字コードとして表示されたのが解せないですが、'_id'が'5d4acf84de925ae437e2c123'のデータが設定した値に置き換わっていることを確認できました。

find_one_and_updateの使い方

これは名前のとおりfind_oneをしてupdateを行うというものです。
動きとしては関数の戻り値として、更新前のデータが取得できます。

(抜粋)MongoUpdateSample.py
mongo = MongoUpdateSample('test', 'salary')
find = mongo.find()
print('--------------------更新前--------------------')
for doc in find:
    print(doc)

update = mongo.find_one_and_update({'name':'山田'},{'$set':{'salary':800000}})
print(type(update))
print(update)
find = mongo.find()
print('--------------------更新後--------------------')
for doc in find:
    print(doc)

実行結果

--------------------更新前--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 300000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000}
<class 'dict'>
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 300000.0}
--------------------更新後--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 800000}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000}

動きとしては、find_oneで見つかったデータに対してupdateを行うようなので、更新件数は一件だけとなるようです。

find_one_and_replaceの使い方

これも名前のとおり、find_oneをして、replaceを行うというものです。
find_one_and_updateと同じく、更新前のデータを取得できます。

(抜粋)MongoUpdateSample.py
mongo = MongoUpdateSample('test', 'salary')
find = mongo.find()
print('--------------------更新前--------------------')
for doc in find:
    print(doc)

update = mongo.find_one_and_replace({'name':'山田'},{'fullname':'山田 太郎','rank':5,'profession':'Engineer','position':'Manager'})
print(type(update))
print(update)
find = mongo.find()
print('--------------------更新後--------------------')
for doc in find:
    print(doc)

実行結果

--------------------更新前--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 800000}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000}
<class 'dict'>
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'name': '山田', 'salary': 800000}
--------------------更新後--------------------
{'_id': ObjectId('5d4acf84de925ae437e2c123'), 'fullname': '山田\u3000太郎', 'rank': 5, 'profession': 'Engineer', 'position': 'Manager'}
{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 400000.0}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000.0}
{'_id': ObjectId('5d4b81a4de925ae437e2c126'), 'name': '山田', 'salary': 500000}

replaceの前の情報を取得することが出来ました。

感想

更新のやり方が普通のSQLにはないreplaceなどのがあり、新鮮でした。
更新のやり方は完全にmongodbのコマンドとパラメーターの渡し方が同じで分かり易かったです。

関連記事

16
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
13