MongoDB
 Computer >> コンピューター >  >> プログラミング >> MongoDB

MongoDBでサブドキュメントの条件を使ってドキュメントをクエリする方法

はじめに

MongoDBでは、配列内に格納されたサブドキュメント(ネストされたドキュメント)の特定のフィールドを条件として、親ドキュメントを検索したいケースがよくあります。本記事では、$expr$let$arrayElemAt を組み合わせることで、配列の最後の要素など特定のサブドキュメントに対して条件を指定し、ドキュメントをクエリする方法を解説します。

サンプルコレクションの作成

まず、ドキュメントを含むコレクションを作成します。ここでは details という配列フィールドを持ち、その中に開始日(startDate)と終了日(endDate)を含む複数のサブドキュメントが格納されたドキュメントを挿入します。

> db.demo394.insertOne(
...    {
...
...       details: [
...       {
...          _id: '1',
...          startDate: '2018-01-11T07:00:00.000Z',
...          endDate: '2019-01-12T07:59:59.999Z'
...       },
...       {
...          _id: '2',
...          startDate: '2019-01-21T07:00:00.000Z',
...          endDate: '2020-01-04T07:59:59.999Z'
...       }
...    ]
... }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e5e716817aa3ef9ab8ab202")
}

挿入したドキュメントの確認

find() メソッドを使用すると、コレクション内のすべてのドキュメントを表示できます。

> db.demo394.find();

実行結果は以下のとおりです。

{
    "_id" : ObjectId("5e5e716817aa3ef9ab8ab202"), "details" : [
       { "_id" : "1", "startDate" : "2018-01-11T07:00:00.000Z", "endDate" : "2019-01-12T07:59:59.999Z" },
       { "_id" : "2", "startDate" : "2019-01-21T07:00:00.000Z", "endDate" : "2020-01-04T07:59:59.999Z" }
    ]
}

サブドキュメントの条件でクエリを実行する

ここからが本題です。配列内の特定のサブドキュメント(この例では最後の要素)のフィールド値を条件に、ドキュメントを検索してみましょう。

使用する主な演算子は以下の3つです。

  • $expr:集計パイプラインの式を通常のクエリ内で使えるようにする演算子
  • $let:変数を定義し、その変数を利用する式を評価する
  • $arrayElemAt:配列から指定インデックスの要素を取得する(-1 を指定すると最後の要素を取得できる)
> db.demo394.find({
...    $expr: {
...       $let: {
...          vars: { "d": { $arrayElemAt: [ "$details", -1 ] } },
...          in: { $eq: [ "$$d.endDate", "2020-01-04T07:59:59.999Z" ] }
...       }
...    }
... })

このクエリの流れは次のとおりです。

  1. $arrayElemAt を使い、details 配列の最後の要素(インデックス -1)を取得する
  2. 取得した要素を変数 d に格納する
  3. $eqd.endDate が指定した日付文字列「2020-01-04T07:59:59.999Z」と一致するかどうかを判定する

実行結果は以下のとおりです。

{
    "_id" : ObjectId("5e5e716817aa3ef9ab8ab202"), "details" : [
       { "_id" : "1", "startDate" : "2018-01-11T07:00:00.000Z", "endDate" : "2019-01-12T07:59:59.999Z" },
       { "_id" : "2", "startDate" : "2019-01-21T07:00:00.000Z", "endDate" : "2020-01-04T07:59:59.999Z" }
    ] 
}

補足:ドット記法との違い

配列内のどれか1つの要素でも条件に一致すればよい場合は、{ "details.endDate": "2020-01-04T07:59:59.999Z" } のようなドット記法でも簡単にクエリできます。一方、今回のように「配列の末尾の要素」や「特定の位置の要素」など、配列内の位置を明示的に指定して条件を付けたい場合には、$expr$arrayElemAt を組み合わせる方法が有効です。

まとめ

$expr$let$arrayElemAt を組み合わせることで、MongoDBの配列内にある任意の位置のサブドキュメントのフィールドを条件に、柔軟にドキュメントを検索できます。特に履歴データや期間情報のように「最新の要素だけを対象に判定したい」ケースで非常に便利なテクニックなので、ぜひ活用してみてください。

  1. MongoDBで埋め込みドキュメント(配列内のサブドキュメント)をクエリする方法

    MongoDBの埋め込みドキュメントをクエリするには?MongoDBでは、ドキュメントの中に配列として埋め込まれたサブドキュメントをクエリする場合、aggregate()メソッドを使用するのが効果的です。この記事では、$unwindと$matchを組み合わせて、埋め込みドキュメントから条件に合うデータを抽出する手順を解説します。1. サンプルコレクションの作成まずは、学生情報を配列として持つドキュメントを含むコレクションを作成しましょう。insertOne()メソッドを使ってドキュメントを挿入します。> db.demo705.insertOne( ... { ...

  2. MongoDBで1つのクエリを使って複数のドキュメントを一括更新する方法(bulkWrite活用ガイド)

    MongoDBで1つのクエリで複数のドキュメントを更新するには?MongoDBで1回のリクエスト(1つのクエリ)で複数のドキュメントを効率的に更新したい場合は、bulkWrite()メソッドを使用します。bulkWrite()は、複数の書き込み操作(insert、update、deleteなど)をまとめてサーバーに送信できるため、個別にクエリを発行するよりもパフォーマンス面で優れています。ここでは、updateOne操作を組み合わせて、複数のドキュメントのフィールドを一度に更新する手順を具体的に解説します。1. コレクションの作成とドキュメントの挿入まず、insertOne()メソッドを使って