MongoDB プロジェクトのネストされたフィールド

Mehvish Ashiq 2023年1月30日
  1. MongoDB プロジェクトのネストされたフィールド
  2. MongoDB で $project 集約ステージを使用してネストされたフィールドをプロジェクトする
  3. MongoDB で $unset 集計ステージを使用して指定されたフィールドを除くネストされたフィールドを取得する
  4. MongoDB で forEach() ループを使用してネストされたフィールドを取得する
  5. MongoDB で mapReduce() メソッドを使用してネストされたフィールドをプロジェクトする
MongoDB プロジェクトのネストされたフィールド

今日は、$project$unset の集計ステージ、forEach() ループ、mapReduce() メソッドを使用して、MongoDB でデータをクエリしながらネストされたフィールドをプロジェクトする方法を学習します。

MongoDB プロジェクトのネストされたフィールド

MongoDB では、find() メソッドを使用してすべてのドキュメントを取得できますが、特定のネストされたフィールドにのみアクセスしたい場合はどうでしょうか。ここでプロジェクトを使用します。

ネストされたフィールドはさまざまな方法でプロジェクトできます。ここでは、ネストされたフィールドをプロジェクトするための次のソリューションについて学習します。

  1. $project 集計ステージを使用します
  2. $unset 集計ステージを使用します
  3. forEach() ループを使用します
  4. mapReduce() 関数を使用します

上記のアプローチを学ぶために、1つのドキュメントを含む nested という名前のコレクションを作成しましょう。また、以下のクエリを使用してフォローアップすることもできます。

サンプルコード:

// MongoDB version 5.0.8

> db.nested.insertOne(
    {
        "name": {
            "first_name": "Mehvish",
            "last_name": "Ashiq",
         },
         "contact": {
            "phone":{"type": "manager", "number": "123456"},
            "email":{ "type": "office", "mail": "delfstack@example.com"}
         },
         "country_name" : "Australien",
         "posting_locations" : [
             {
                 "city_id" : 19398,
                 "city_name" : "Bondi Beach (Sydney)"
             },
             {
                  "city_id" : 31101,
                  "city_name" : "Rushcutters Bay (Sydney)"
             },
             {
                  "city_id" : 31022,
                  "city_name" : "Wolly Creek (Sydney)"
             }
          ],
          "regions" : {
              "region_id" : 796,
              "region_name" : "Australien: New South Wales (Sydney)"
          }
    }
);

db.nested.find().pretty(); を使用します挿入されたデータを確認するには、mongo シェルで。

MongoDB で $project 集約ステージを使用してネストされたフィールドをプロジェクトする

サンプルコード:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> var project = {};
> project["id"] = "$"+current_location+".city_id";
> project["name"] = "$"+current_location+".city_name";
> project["regions"] = 1;

> var find = {};
> find[current_location] = {"$exists":true};

> db.nested.aggregate([
    { $match : find },
    { $project : project }
]).pretty()

出力:

{
        "_id" : ObjectId("62a96d397c7e3688aea26d0d"),
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "id" : [
                19398,
                31101,
                31022
        ],
        "name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

ここでは、posting_locations という名前の第 1 レベルのフィールドを current_location という変数に保存します。

次に、その変数を使用して city_idcity_name にアクセスし、ブラケット表記を使用して project オブジェクトのプロパティを作成しながら、それらを project オブジェクトに保存します。さらに、project["regions"]regions フィールドを保存します。

次に、aggregate() メソッドでドキュメントを照合するために使用する find という名前の別のオブジェクトがあります。aggregate() メソッドでは、$match ステージを使用してドキュメントを照合し、$project を使用してネストされているか最初のレベルであるかに関係なくフィールドをプロジェクトします。

$project を使用して、出力に表示するフィールドを指定します。フィルタクエリを使用せずに、指定されたネストされたフィールドのみをプロジェクトする場合は、次のソリューションを使用できます。

サンプルコード:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> db.nested.aggregate({
    $project: {
         "_id": 0,
         "city_id": "$" + current_location + ".city_id",
         "city_name": "$" + current_location + ".city_name",
         "regions": 1
    }
}).pretty();

出力:

{
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "city_id" : [
                19398,
                31101,
                31022
        ],
        "city_name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

MongoDB で $unset 集計ステージを使用して指定されたフィールドを除くネストされたフィールドを取得する

サンプルコード:

// MongoDB version 5.0.8

> db.nested.aggregate({
        $unset: ["posting_locations.city_id", "contact", "regions", "name", "_id"]
}).pretty()

出力:

{
        "country_name" : "Australien",
        "posting_locations" : [
                {
                        "city_name" : "Bondi Beach (Sydney)"
                },
                {
                        "city_name": "Rushcutters Bay (Sydney)"
                },
                {
                        "city_name": "Wolly Creek (Sydney)"
                }
        ]
}

ここでは、$unset 演算子を使用します。この演算子は、指定されたフィールドまたはフィールドの配列を削除するために使用されます。

埋め込みドキュメントまたはドキュメントの配列を指定するためにドット表記を使用することを忘れないでください。指定されたフィールドが存在しない場合、$unset 演算子は操作を実行しません。

$ を使用して配列の要素を照合する場合、$unset 演算子は、一致する要素を配列から削除するのではなく、null に置き換えます。この動作は、要素の位置と配列サイズの一貫性を維持するのに役立ちます。

MongoDB で forEach() ループを使用してネストされたフィールドを取得する

サンプルコード:

// MongoDB version 5.0.8

> var bulk = db.newcollection.initializeUnorderedBulkOp(),
   counter = 0;

> db.nested.find().forEach(function(doc) {
    var document = {};
    document["name"] = doc.name.first_name + " " + doc.name.last_name;
    document["phone"] = doc.contact.phone.number;
    document["mail"] = doc.contact.email.mail;
    bulk.insert(document);
    counter++;
    if (counter % 1000 == 0) {
        bulk.execute();
        bulk = db.newcollection.initializeUnorderedBulkOp();
    }
});

> if (counter % 1000 != 0) { bulk.execute(); }

次のようなものが表示されます。

BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 1,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})

次に、mongo シェルで以下のコマンドを実行して、プロジェクトされたフィールドを確認します。

// MongoDB version 5.0.8

> db.newcollection.find().pretty();

出力:

{
        "_id" : ObjectId("62a96f2d7c7e3688aea26d0e"),
        "name" : "Mehvish Ashiq",
        "phone" : "123456",
        "mail" : "delfstack@example.com"
}

このサンプルコードを学習するために、特定のネストされたフィールドを取得して、それらを新しいコレクションに挿入するとします。ここで、変換されたフィールドをドキュメントとして新しいコレクションに挿入すると、ネストされたコレクションのサイズに基づいて操作に影響を与える可能性があります。

新しい順序付けされていない一括挿入API を使用することで、この遅い挿入パフォーマンスを回避できます。一括送信することで挿入操作を合理化し、操作が成功したか失敗したかについてリアルタイムでフィードバックを提供します。

そのため、bulk insert API を使用して、目的のデータ構造を newcollection コレクションに挿入します。ここで、新しいドキュメントは、nested コレクションカーソルの forEach() ループで作成されます。新しいプロパティを作成するには、括弧表記を使用します。

このコードでは、大量のデータがあると想定しています。そのため、一括挿入操作を実行するために、1000 のバッチでサーバーに操作を送信します。

その結果、各リクエストを送信するのではなく、サーバーへの 1000 リクエストごとに 1 回だけ送信するため、優れたパフォーマンスが得られます。

MongoDB で mapReduce() メソッドを使用してネストされたフィールドをプロジェクトする

サンプルコード:

// MongoDB version 5.0.8

> function map() {
    for(var i in this.posting_locations) {
         emit({
             "country_id" : this.country_id,
             "city_id" : this.posting_locations[i].city_id,
             "region_id" : this.regions.region_id
         },1);
    }
}

> function reduce(id,docs) {
      return Array.sum(docs);
}

> db.nested.mapReduce(map,reduce,{ out : "map_reduce_output" } )

次に、次のクエリを実行して出力を確認します。

// MongoDB version 5.0.8
> db.map_reduce_output.find().pretty();

出力:

{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 19398,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31022,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31101,
                "region_id" : 796
        },
        "value" : 1
}

このサンプルコードでは、mapReduce() 関数を使用して、nested コレクションのすべてのドキュメントに対して map-reduce を実行します。そのためには、以下に簡単に説明する 3つのステップのプロセスに従う必要があります。

  • すべての入力ドキュメントを処理するための map() 関数を定義します。この関数では、this キーワードは map-reduce 操作によって処理されている現在のドキュメントを参照し、emit() 関数は指定された値をキーにマップして返します。
  • ここでは、対応する reduce() 関数を定義します。これは、データの集約が行われる実際の場所です。2つの引数(キー)を取ります。このコード例では、iddocs を使用しています。

    docs の要素は、map() メソッドから emit() 関数によって返されることに注意してください。このステップで、reduce() 関数は docs 配列をその値(要素)の合計に減らします。

  • 最後に、map() および reduce() 関数を使用して、nested コレクション内のすべてのドキュメントに対して map-reduce を実行します。out を使用して、指定されたコレクション(この場合は map_reduce_output)に出力を保存します。
著者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

関連記事 - MongoDB Projection