pymongo findでできることはaggregateではしない

投稿者: | 2020-01-06

pymongoではなるべくaggregateでなく、findを使いたい。なので、findの引数をメモ。

aggregateは、パイプラインを使って色々できるが、個人的にはfindで実現できない場合だけ使いたい。($unwindなど)

find自体のドキュメントは、 collection – Collection level operations — PyMongo 3.9.0 documentation にある。次のような引数をとる。

find(filter=None, projection=None, skip=0, limit=0, no_cursor_timeout=False, cursor_type=CursorType.NON_TAILABLE, sort=None, allow_partial_results=False, oplog_replay=False, modifiers=None, batch_size=0, manipulate=True, collation=None, hint=None, max_scan=None, max_time_ms=None, max=None, min=None, return_key=False, show_record_id=False, snapshot=False, comment=None, session=None)

クエリの条件指定で使えそうなのは、以下のものだろう。

  • filter
    • 大体必ず使うはず。説明は不要だと思う。実質$matchみたいなもの。
  • projection
    • 特定のフィールドだけ抽出したり、省略したりできる。
  • skip
    • ここに指定した整数の分だけ、結果のドキュメント群の先頭をスキップできる。
  • limit
    • 指定数だけのドキュメントを取得する。
  • sort
    • ソートを指定できる。タプルのリストを指定する。

ドキュメントの構造は次のようなものとする。実用性は無視。

  • books: コレクション名
    • title: 本のタイトルとなる文字列
    • price: 価格
    • category: 本のカテゴリ
    • author: 著者
    • tags: 本をタグで仕分けるためのタグ。複数なのでリスト。
    • timestamp: ドキュメント追加日時

次のようなaggregateのパイプラインがあるとき、

pipeline = [
    {'$match': {'tags': {'$in': ['action']}}},
    {'$project': {'timestamp': False}},
    {'$sort': {'price': -1, 'title': 1}}
]
cur = db.books.aggregate(pipeline)
docs = [doc for doc in cur]  # ドキュメントのリスト

これは、タグにactionを含むドキュメント群を、ドキュメント追加日時は含めず、価格降順・タイトル昇順で取り出すことができる。これをfindで実装すると、

cur = db.books.find({'tags': {'$in': ['action']}},
              projection={'timestamp': False},
              sort=[('price', -1), ('title', 1)])
docs = [doc for doc in cur]

となる。$projectprojectionになったりはするが、スッキリする。 さらに、ページネートを考えた時、skiplimitでインデックスの扱いが簡単になるのはいいことだと思う。

以上です。Thanks for reading!


広告