pymongoとMongoDBでNo SQLが楽しくなる!

2020年3月3日火曜日

MongoDB Python

t f B! P L

pymongoとMongoDBでNo SQLが楽しくなる!

はじめに

Python + pymongoでMongoDBにアクセスする方法を解説します。MongoDBは世界的に人気のNoSQL DBで、DBMSをランキングしているDB-Enginesでは、Oracle、MySQLなどに次いで、5位になっています。

この記事を書くにあたって使用した環境は、以下の通りです。

Python 3.7
pymongo-3.10.1
MongoDB 4.2

前提データ

users.insert_one({ "id": 1, "name": "山田 太郎", "age": 20 })
users.insert_one({ "id": 2, "name": "山田 次郎", "age": 25 })
users.insert_one({ "id": 3, "name": "山田 三郎", "age": 40 })
users.insert_one({ "id": 4, "name": "鈴木 一郎", "age": 40 })
users.insert_one({ "id": 5, "name": "鈴木 次郎", "age": 60 })
id name age
1 山田 太郎 20
2 山田 次郎 25
3 山田 三郎 40
4 鈴木 一郎 40
5 鈴木 次郎 60

接続

pymongoでMongoDBには、次のように記述します。

from pymongo import MongoClient

client = MongoClient("mongodb://user:password@localhost:27017")

# DB接続(存在しない場合は作成)
db = client["testdb"]

# コレクションに接続(存在しない場合は作成)
users = db["users"]

検索条件を指定

条件指定はfind関数の引数で指定する

コレクションから条件指定でデータを抽出する場合は、次のように書きます。RDBで言うWHERE句の部分です。

results = users.find({ 'age': 40 })

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }

AND条件で複数条件を指定する

複数のAND条件を指定する場合は、次のように$andの中に条件をリストで渡します。

results = users.find(filter={'$and': [ {'name':'ユーザ3'}, {'age':40} ] })

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }

OR条件で複数条件を指定する

OR条件もANDと同じように、$orの中に条件をリストで渡します。

results = users.find(filter={'$or': [ {'name':'ユーザ1'}, {'age':40} ] })

▪️ 実行結果

{ id: 1, name: 山田 太郎, age: 20 }
{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }

AND・OR条件が混在するパターン

ANDとOR条件が混在するようなケースも、次のように記述して検索できます。

results = users.find(filter={'$or': [ 
    { '$and': [ {'name': "ユーザ1"}, {'age': 20} ] },
    { '$and': [ {'name': "ユーザ5"}, {'age': 60} ] },
  ]})

▪️ 実行結果

{ id: 1, name: 山田 太郎, age: 20 }
{ id: 5, name: 鈴木 次郎, age: 60 }

あまり条件が複雑になると可読性や性能に影響するので、効率的なデータアクセスができるモデル設計を心がけましょう!

部分一致で検索する

部分一致は、正規表現で書きます。正規表現で検索できるので、複雑な文字列検索もシンプルに書けそうです。

results = users.find(filter={'name':{'$regex':'鈴木|次郎'}})

▪️ 実行結果

{ id: 2, name: 山田 次郎, age: 25 }
{ id: 4, name: 鈴木 一郎, age: 40 }
{ id: 5, name: 鈴木 次郎, age: 60 }

範囲検索「○○以上($gte)」

範囲検索はそれぞれ以下のように書きます。MongoDBでの範囲指定の書き方は、残念ながらRDBのSQLに比べ少し見にくいです。

次のように書くと「年齢 ≧ 40」のような条件で検索できる。

results = users.find(filter={'age':{'$gte': 40}})

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }
{ id: 5, name: 鈴木 次郎, age: 60 }

範囲検索「○○以下($lte)」

「年齢 ≦ 40」のように検索する場合は、次の通り。

results = users.find(filter={'age':{'$lte': 40}})

▪️ 実行結果

{ id: 1, name: 山田 太郎, age: 20 }
{ id: 2, name: 山田 次郎, age: 25 }
{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }

範囲検索「○○より上($gt)」

「年齢 > 40」の場合。

{ id: 5, name: 鈴木 次郎, age: 60 }

▪️ 実行結果

{ id: 1, name: 山田 太郎, age: 20 }
{ id: 2, name: 山田 次郎, age: 25 }

範囲検索「○○より下($lt)」

「年齢 < 40」の場合。

results = users.find(filter={'age':{'$lt': 40}})

▪️ 実行結果

{ id: 1, name: 山田 太郎, age: 20 }
{ id: 2, name: 山田 次郎, age: 25 }

sort (ソート・並び替え)

並び替えは、そのままsort関数を使う。第1引数にはソートを行う項目名、第2には、昇順pymongo.ASCENDING、降順pymongo.DESCENDINGのどちらかを指定する。第2引数を省略した場合は昇順ソートになる。

results = users.\
  find().\
  sort("id", pymongo.DESCENDING)

▪️ 出力結果

{ id: 5, name: ユーザ5, age: 60 }
{ id: 4, name: ユーザ4, age: 40 }
{ id: 3, name: ユーザ3, age: 40 }
{ id: 2, name: ユーザ2, age: 25 }
{ id: 1, name: ユーザ1, age: 20 }

データの登録

MongoDBにデータを登録する時は、insert_oneまたはinsert_manyを使用します。

1件データを登録 (insert_one)

insert_oneは、データを1件を登録する関数です。

users.insert_one({ "id": 1, "name": "山田 太郎", "age": 20 })

複数件のデータを一括登録 (insert_many)

insert_manyは、リストで登録するデータを指定できます。複数件のデータをまとめて登録したい場合は、こちらの関数を使用します。

users.insert_many([
  { "id": 1, "name": "鈴木 一郎", "age": 60 },
  { "id": 2, "name": "鈴木 次郎", "age": 40 },
  { "id": 3, "name": "鈴木 三郎", "age": 30 }
])

データの更新

データの更新は、update_oneまたはupdate_manyを使用します。

1件データを更新 (update_one)

条件に一致する先頭1件のデータを更新する場合は、update_oneを使用します。次のサンプルコードは、年齢を40→50歳に更新する例です。

users.update_one({"age": 40}, { "$set": { "age": 50 }})

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }
↓ 更新後 ↓ 
{ id: 3, name: 山田 三郎, age: 50 }
{ id: 4, name: 鈴木 一郎, age: 40 }

上の結果から見て取れるように、条件に一致するデータが複数件あっても、update_one関数は見つかった先頭1件目のデータしか更新しません。

複数のデータを更新 (update_many)

条件に一致するデータを全て更新する場合は、update_manyを使用します。

users.update_many({"age": 40}, { "$set": { "age": 50 }})

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }
↓ 更新後 ↓ 
{ id: 3, name: 山田 三郎, age: 50 }
{ id: 4, name: 鈴木 一郎, age: 50 }

上記以外に、update関数を使用する方法もあります。

データの削除

データの更新は、delete_oneまたはdelete_manyを使用します。

1件データを削除 (delete_one)

条件に一致する先頭1件のデータを削除する時は、delete_oneを使用します。

users.delete_one({"age": 40})

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }
↓ 削除後 ↓ 
{ id: 4, name: 鈴木 一郎, age: 40 }

複数件のデータを削除 (delete_many)

条件に一致するデータを全て削除する時は、delete_manyを使用します。

users.delete_many({"age": 40})

▪️ 実行結果

{ id: 3, name: 山田 三郎, age: 40 }
{ id: 4, name: 鈴木 一郎, age: 40 }
↓ 削除後 ↓ 
なし

全てのドキュメントを削除 (drop)

コレクション内のすべてのドキュメントを削除する時は、dropを使用します。

users.drop()

まとめ

No SQLのMongoDBは、テーブル(コレクション)の構造が後から拡張できて、パッと使えて便利です。

スポンサーリンク

QooQ