LoginSignup
16
16

More than 3 years have passed since last update.

pymongoを使った様々な検索条件(AND/OR/部分一致/範囲検索)

Posted at

当記事の記載範囲

この記事ではPythonでmongodbに接続後、findを使った様々な検索方法を記載しています。
1. AND
2. OR
3. 部分一致
4. 前方一致
5. 後方一致
6. 範囲検索(BETWEEN)

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("5d4acf84de925ae437e2c124"), "name" : "佐藤", "salary" : 450000, "depId" : "A0001" }
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000, "depId" : "A0001" }
{ "_id" : ObjectId("5d4f814c950945628d663d95"), "name" : "加藤", "salary" : 400000, "depId" : "B0001" }
{ "_id" : ObjectId("5d4f814c950945628d663d96"), "name" : "松井", "salary" : 500000, "depId" : "C0001" }
{ "_id" : ObjectId("5d5179f76427f268db46299f"), "name" : "山田", "salary" : 500000, "depId" : "A0002" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

様々な検索方法

検索方法がmongodbのコマンドと結構違っているところがあったので、mongodbのコマンドと比較しながら記載します。
pymongoを使ったコードは以下の内容を使用しています。

MongoFindSample.py
from pymongo import MongoClient
from pymongo import DESCENDING
from pymongo import ASCENDING
from matplotlib import pyplot

class MongoFindSample(object):

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

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

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

    def count_documents(self, filter=None):
        return self.collection.count_documents(filter)


mongo = MongoFindSample('test', 'salary')

ANDの使い方

collection"salary"からnameフィールドが"山田" かつ depIdフィールドが"C0002"のデータを取得します。
まずは、mongodbのコマンド

> db.salary.find({$and:[{'name':'山田'},{'depId':'C0002'}]})
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

次はpymongoを使った書き方

MongoFindSample.py
result1 = mongo.find(filter={'$and':[{'name':'山田'},{'depId':'C0002'}]})
for doc in result1:
    print(doc)

実行結果

{'_id': ObjectId('5d5216ab61aa9ee6159ad4d8'), 'name': '山田', 'salary': 300000, 'depId': 'C0002'}

ANDについては$andをシングルクォーテーションで囲むか囲まないかという違いしかありませんでした。

ORの使い方

collection"salary"からnameフィールドが"山田" または depIdフィールドが"B0001"のデータを取得します。
まずは、mongodbのコマンド

> db.salary.find({$or:[{'name':'山田'},{'depId':'B0001'}]})
{ "_id" : ObjectId("5d4f814c950945628d663d95"), "name" : "加藤", "salary" : 400000, "depId" : "B0001" }
{ "_id" : ObjectId("5d5179f76427f268db46299f"), "name" : "山田", "salary" : 500000, "depId" : "A0002" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

pymongoを使った書き方

MongoFindSample.py
result1 = mongo.find(filter={'$or':[{'name':'山田'},{'depId':'B0001'}]})
for doc in result1:
    print(doc)

実行結果

{'_id': ObjectId('5d4f814c950945628d663d95'), 'name': '加藤', 'salary': 400000, 'depId': 'B0001'}
{'_id': ObjectId('5d5179f76427f268db46299f'), 'name': '山田', 'salary': 500000, 'depId': 'A0002'}
{'_id': ObjectId('5d5216ab61aa9ee6159ad4d8'), 'name': '山田', 'salary': 300000, 'depId': 'C0002'}

ORはANDと同じくシングルクォーテーションで囲むか囲まないかという違いだけでした。

部分一致の使い方

nameに"田"を含むデータを取得してみます。

> db.salary.find({"name":/田/}))
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000, "depId" : "A0001" }
{ "_id" : ObjectId("5d5179f76427f268db46299f"), "name" : "山田", "salary" : 500000, "depId" : "A0002" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

次はpymongoの使い方

MongoFindSample.py
result1 = mongo.find(filter={'name':{'$regex':'田'}})
for doc in result1:
    print(doc)

実行結果

{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000, 'depId': 'A0001'}
{'_id': ObjectId('5d5179f76427f268db46299f'), 'name': '山田', 'salary': 500000, 'depId': 'A0002'}
{'_id': ObjectId('5d5216ab61aa9ee6159ad4d8'), 'name': '山田', 'salary': 300000, 'depId': 'C0002'}

これは書き方がかなり違いますね。
pymongoの方の書き方は"name"に対して正規表現を使いますというような書き方になっています。
また、正規表現のパターンの前後のスラッシュもpymongoでは不要なようです。

前方一致の使い方

"depId"がAで始まるデータを取得してみます。
まずはmongodbのコマンド

> db.salary.find({"depId":/^A/})
{ "_id" : ObjectId("5d4acf84de925ae437e2c124"), "name" : "佐藤", "salary" : 450000, "depId" : "A0001" }
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000, "depId" : "A0001" }
{ "_id" : ObjectId("5d5179f76427f268db46299f"), "name" : "山田", "salary" : 500000, "depId" : "A0002" }

次はpymongoの使い方

MongoFindSample.py
result1 = mongo.find(filter={'depId':{'$regex':'^A'}})
for doc in result1:
    print(doc)

実行結果

{'_id': ObjectId('5d4acf84de925ae437e2c124'), 'name': '佐藤', 'salary': 450000, 'depId': 'A0001'}
{'_id': ObjectId('5d4acf84de925ae437e2c125'), 'name': '田中', 'salary': 500000, 'depId': 'A0001'}
{'_id': ObjectId('5d5179f76427f268db46299f'), 'name': '山田', 'salary': 500000, 'depId': 'A0002'}

前方一致の場合は^が最初に必要になります。

後方一致の使い方

"depId"が"2"で終わるデータを取得してみます。
まずは、mongodbのコマンド

> db.salary.find({"depId":/2$/})
{ "_id" : ObjectId("5d5179f76427f268db46299f"), "name" : "山田", "salary" : 500000, "depId" : "A0002" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

次はpymongoの使い方

MongoFindSample.py
result = mongo.find(filter={'depId':{'$regex':'2$'}})
for doc in result:
    print(doc)

実行結果

{'_id': ObjectId('5d5179f76427f268db46299f'), 'name': '山田', 'salary': 500000, 'depId': 'A0002'}
{'_id': ObjectId('5d5216ab61aa9ee6159ad4d8'), 'name': '山田', 'salary': 300000, 'depId': 'C0002'}

後方一致の場合は末尾に$マークが必要です。

範囲検索(BETWEEN)

mongodbにはBETWEENが無いみたいなので、AND条件を組み合わせて行う必要があります。
salaryフィールドが300000以上、400000以下のデータを取得してみます。

> db.salary.find({$and:[{'salary':{$gte:300000}},{'salary':{$lte:400000}}]})
{ "_id" : ObjectId("5d4f814c950945628d663d95"), "name" : "加藤", "salary" : 400000, "depId" : "B0001" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }

次はpymongoの使い方

MongoFindSample.py
result1 = mongo.find(filter={'$and':[{'salary':{'$gte':300000}},{'salary':{'$lte':400000}}]})
for doc in result1:
    print(doc)

実行結果

{'_id': ObjectId('5d4f814c950945628d663d95'), 'name': '加藤', 'salary': 400000, 'depId': 'B0001'}
{'_id': ObjectId('5d5216ab61aa9ee6159ad4d8'), 'name': '山田', 'salary': 300000, 'depId': 'C0002'}

長いな。。
次の書き方でも同じ結果を得られました。

> db.salary.find({'salary':{$gte:300000,$lte:400000}})
{ "_id" : ObjectId("5d4f814c950945628d663d95"), "name" : "加藤", "salary" : 400000, "depId" : "B0001" }
{ "_id" : ObjectId("5d5216ab61aa9ee6159ad4d8"), "name" : "山田", "salary" : 300000, "depId" : "C0002" }
MongoFindSample.py
result1 = mongo.find(filter={'salary':{'$gte':300000,'$lte':400000}})

内部の動きまでは分かりませんが、こちらの方が書き方がシンプルで分かり易いですね。

感想

部分一致以外はmongodbのコマンドと同じものをpymongoで使えました。
ANDのは複数の書き方が出来るみたいなので、違いを細かく調べる必要がありそうです。

関連記事

16
16
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
16