1. ホーム
  2. mongodb

[解決済み] MongoDB - シンプルなサブクエリの例

2022-02-10 08:48:07

質問

データがある。

> db.parameters.find({})
{ "_id" : ObjectId("56cac0cd0b5a1ffab1bd6c12"), "name" : "Speed", "groups" : [ "
123", "234" ] }
> db.groups.find({})
{ "_id" : "123", "name" : "Group01" }
{ "_id" : "234", "name" : "Group02" }
{ "_id" : "567", "name" : "Group03" }

を供給したい。 パラメータ _id に含まれるすべてのグループをクエリで返します。 グループ で指定されたドキュメントの配列 パラメータ テーブルを作成します。

素直な解決策は、PyMongoで何度かDBを呼び出すことみたいです。

  1. からのパラメータ取得 パラメータ テーブルで指定された _id に基づいて
  2. の各要素に対して グループ 配列からドキュメントを選択します。 グループ コレクション

しかし、これでは無駄なオーバーヘッドが多くなってしまいます。MongoDB内で(DB内でカスタムJSを実行せずに)これを行うための、より良い、より速い方法があるはずだと感じています。それとも、ドキュメントベースのアプローチを無視して、データを少し正規化して(リレーションシップのテーブルのように)再構築するべきでしょうか?

繰り返しますが、PyMongo DBのインターフェースから動作するソリューションを見つけるのを助けてください。

どのように解決するのですか?

アグリゲーションフレームワークを使用して、1つのクエリ内でこれを行うことができます。具体的には、アグリゲーションパイプラインを実行する必要があります。 $lookup 演算子で左結合を行います。 parameters コレクションから groups コレクションを作成します。

次のようなパイプラインの実行を考えてみましょう。

db.parameters.aggregate([
    { "$unwind": "$groups" },
    {
        "$lookup": {
            "from": "groups",
            "localField": "groups",
            "foreignField": "_id",
            "as": "grp"
        }
    },
    { "$unwind": "$grp" }
])

サンプル出力

/* 1 */
{
    "_id" : ObjectId("56cac0cd0b5a1ffab1bd6c12"),
    "name" : "Speed",
    "groups" : "123",
    "grp" : {
        "_id" : "123",
        "name" : "Group01"
    }
}

/* 2 */
{
    "_id" : ObjectId("56cac0cd0b5a1ffab1bd6c12"),
    "name" : "Speed",
    "groups" : "234",
    "grp" : {
        "_id" : "234",
        "name" : "Group02"
    }
}


お使いのMongoDBサーバーのバージョンが、この機能をサポートしていない場合 $lookup パイプライン演算子を使用する場合、次のように2つのクエリを実行する必要があります。

# get the group ids
ids = db.parameters.find_one({ "_id": ObjectId("56cac0cd0b5a1ffab1bd6c12") })["groups"]

# query the groups collection with the ids from previous query
db.groups.find({ "_id": { "$in": ids } })

EDIT: 集計クエリのフィールド名とサンプルデータセット(質問内)のフィールド名を一致させました。