web-dev-qa-db-ja.com

MongoDB-単純なサブクエリの例

与えられたデータ:

> 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" }

parametersテーブル内の指定されたドキュメントのgroups配列内にあるすべてのグループをクエリが返すようにするparameters _idを指定します。

簡単な解決策は、PyMongoでいくつかのDB呼び出しを行うようです:

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

しかし、これには非常に多くの不必要なオーバーヘッドがあります。 (DBでカスタムJSを実行せずに)MongoDB内でこれを行うには、より良い、より高速な方法が必要だと思います。または、ドキュメントベースのアプローチを無視して、データを少し(正規化の表のように)正規化して再構成する必要がありますか?

繰り返しますが、PyMongo DBインターフェースから機能するソリューションを見つけるのを手伝ってください

5
Tony Sepia

これは、集計フレームワークを使用して単一のクエリ内で実行できます。特に、左結合を行うには$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 } })

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

7
chridam