2016-03-15 9 views
10

データベースから単一のオブジェクト階層全体をJSONとして取得する必要があります。実際には、この結果を達成するための他の解決策に関する提案は非常に憂慮されるでしょう。私はMongoDBの$ルックアップをサポートすることに決めました。3レベルのMongoDBネストされたルックアップ

パーティ

{ "_id" : "2", "name" : "party2" } 
{ "_id" : "5", "name" : "party5" } 
{ "_id" : "4", "name" : "party4" } 
{ "_id" : "1", "name" : "party1" } 
{ "_id" : "3", "name" : "party3" }  

アドレス

{ "_id" : "a3", "street" : "Address3", "party_id" : "2" } 
{ "_id" : "a6", "street" : "Address6", "party_id" : "5" } 
{ "_id" : "a1", "street" : "Address1", "party_id" : "1" } 
{ "_id" : "a5", "street" : "Address5", "party_id" : "5" } 
{ "_id" : "a2", "street" : "Address2", "party_id" : "1" } 
{ "_id" : "a4", "street" : "Address4", "party_id" : "3" } 

addressComment

は、だから私は3つのコレクションを持っています

{ "_id" : "ac2", "address_id" : "a1", "comment" : "Comment2" } 
{ "_id" : "ac1", "address_id" : "a1", "comment" : "Comment1" } 
{ "_id" : "ac5", "address_id" : "a5", "comment" : "Comment6" } 
{ "_id" : "ac4", "address_id" : "a3", "comment" : "Comment4" } 
{ "_id" : "ac3", "address_id" : "a2", "comment" : "Comment3" } 

レコードの一部としてすべての対応する住所とコメントを持つすべての当事者を取得する必要があります。私の集計:

db.party.aggregate([{ 
    $lookup: { 
     from: "address", 
     localField: "_id", 
     foreignField: "party_id", 
     as: "address" 
    } 
}, 
{ 
    $unwind: "$address" 
}, 
{ 
    $lookup: { 
     from: "addressComment", 
     localField: "address._id", 
     foreignField: "address_id", 
     as: "address.addressComment" 
    } 
}]) 

結果はかなり変です。いくつかのレコードはOKです。しかし、_id 4のパーティーはありません(アドレスはありません)。また、結果セットには2つのParty _id 1があります(住所は異なります)。

{ 
    "_id": "1", 
    "name": "party1", 
    "address": { 
     "_id": "2", 
     "street": "Address2", 
     "party_id": "1", 
     "addressComment": [{ 
      "_id": "3", 
      "address_id": "2", 
      "comment": "Comment3" 
     }] 
    } 
}{ 
    "_id": "1", 
    "name": "party1", 
    "address": { 
     "_id": "1", 
     "street": "Address1", 
     "party_id": "1", 
     "addressComment": [{ 
      "_id": "1", 
      "address_id": "1", 
      "comment": "Comment1" 
     }, 
     { 
      "_id": "2", 
      "address_id": "1", 
      "comment": "Comment2" 
     }] 
    } 
}{ 
    "_id": "3", 
    "name": "party3", 
    "address": { 
     "_id": "4", 
     "street": "Address4", 
     "party_id": "3", 
     "addressComment": [] 
    } 
}{ 
    "_id": "5", 
    "name": "party5", 
    "address": { 
     "_id": "5", 
     "street": "Address5", 
     "party_id": "5", 
     "addressComment": [{ 
      "_id": "5", 
      "address_id": "5", 
      "comment": "Comment5" 
     }] 
    } 
}{ 
    "_id": "2", 
    "name": "party2", 
    "address": { 
     "_id": "3", 
     "street": "Address3", 
     "party_id": "2", 
     "addressComment": [{ 
      "_id": "4", 
      "address_id": "3", 
      "comment": "Comment4" 
     }] 
    } 
} 

これを手伝ってください。私はMongoDBにはかなり新しいですが、私はそれが私が必要とすることができると感じています。

答えて

19

「トラブル」の原因は、2番目の集計段階です。{ $unwind: "$address" }です。 _id: 4のパーティーのレコードを削除します(アドレス配列が空であるため)。_id: 1_id: 5の2つのレコードが生成されます(それぞれに2つのアドレスがあるため)。あなたはtrue$unwindステージのpreserveNullAndEmptyArraysオプションを設定する必要がありますアドレスせず、当事者の除去防止するため

  • 異なるアドレスの当事者が重複しないようにするには、パイプラインに$groupアグリゲーションステージを追加する必要があります。また、$filter演算子を使用して$projectステージを使用して、出力で空のアドレスレコードを除外します。

db.party.aggregate([{ 
    $lookup: { 
    from: "address", 
    localField: "_id", 
    foreignField: "party_id", 
    as: "address" 
    } 
}, { 
    $unwind: { 
    path: "$address", 
    preserveNullAndEmptyArrays: true 
    } 
}, { 
    $lookup: { 
    from: "addressComment", 
    localField: "address._id", 
    foreignField: "address_id", 
    as: "address.addressComment", 
    } 
}, { 
    $group: { 
    _id : "$_id", 
    name: { $first: "$name" }, 
    address: { $push: "$address" } 
    } 
}, { 
    $project: { 
    _id: 1, 
    name: 1, 
    address: { 
     $filter: { input: "$address", as: "a", cond: { $ifNull: ["$$a._id", false] } } 
    } 
    } 
}]); 
+0

戦車あなたシャッド !レコード4と一つの小さな問題は、しかしある: '{ \t "_id": "4"、 \t "名前": "party4"、 \t "アドレス":[{ \t \t "addressComment":[] \t} } あなたが見ることができるように、アドレスはnullでなければなりませんが、代わりに空のレコードです... addressCommentが空の場合、アドレスをスキップできますか?それ以外の場合、このアドレスはレコードと見なされます。 – Yuriy

+1

実際には、$ unwind操作の新しい "preserveNullAndEmptyArrays"フィールド(3.2以降)の説明に従って、提供されたソリューションが期待通りに機能することがわかります。これで、 "$ unwind:{path:" $ address "、preserveNullAndEmptyArrays:true}'の代わりに、 "$ project"ステップをスキップしてこの "$ unwind"を指定することができます。私はあなたの答えを受け入れる、迅速かつ明確な応答をありがとう! – Yuriy

+0

@Shad私は全く同じような質問があります。ここでOPのコードには 'party'コレクションに' name'というプロパティが1つしかないので、 '$ group'で' $ first 'を使用しました。私は10以上のプロパティを持っていると仮定して、自動的にすべてのプロパティを個別に言及せずに取得する方法はありますか? – Xyroid

関連する問題