2017-10-25 1 views
1

これはlocationsコレクションデータです。2つの異なるコレクションにあるオブジェクトの配列からフィールドにアクセスする方法は?

{ 
    _id: "1", 
    location: "loc1", 
    sublocations: [ 
    { 
     _id: 2, 
     sublocation: "subloc1", 
    }, 
    { 
     _id: 3, 
     sublocation: "subloc2", 
    } 
    ] 
}, 
{ 
    _id: "4", 
    location: "loc2", 
    sublocations: [ 
    { 
     _id: 5, 
     sublocation: "subloc1", 
    }, 
    { 
     _id: 6, 
     sublocation: "subloc2", 
    } 
    ] 
} 

これは、今、私は価格の配列における製品スキーマ内sublocationを取得する必要がありproducts収集データ

{ 
    _id: "1", 
    product: "product1", 
    prices: [ 
    { 
     _id: 2, 
     sublocationid: 2,  //ObjectId of object in sublocations array 
     price: 500 
    }, 
    { 
     _id: 3, 
     sublocationid: 5,  //ObjectId of object in sublocations array 
     price: 200 
    } 
    ] 
} 

です。期待される結果は以下の通りです。

{ 
    _id: "1", 
    product: "product1", 
    prices: [ 
    { 
     _id: 2, 
     sublocationid: 3, 
     sublocation: "subloc2", 
     price: 500 
    }, 
    { 
     _id: 3, 
     sublocationid: 5, 
     sublocation: "subloc1" 
     price: 200 
    } 
    ] 
} 

これを実現するには、次のようにしました。

  • まず、locationsコレクションで集計を実行します。 - $は、サブロケーション配列をアンワインドし、$ outを新しいコレクションに格納します。
  • 第2に、 'products'コレクションで集約を実行します。$は価格をアンワインドし、$は新しいコレクションからsublocationidを検索し、$それらをグループ化します。
  • 第3に、データを取得した後、新しいコレクションのデータを削除します。

その他の簡単な方法はありますか?もしあれば教えてください。

+0

結果セットの例を教えてください。簡略化されたクエリを提供する点で非常に役に立ちます。 – cbartosiak

+0

別の質問 - グローバルにユニークなサブロケーションIDですか? – cbartosiak

+0

私は別の質問を思いつきました - それは価格配列の文字列としてsublocation idsとintとしてsublocations配列にあるtypoですか? – cbartosiak

答えて

1

あなたは3.4バージョンに固執する場合は、このクエリを試すことができます。

db.products.aggregate([ 
    { 
     $unwind: { 
      "path": "$prices" 
     } 
    }, 
    { 
     $lookup: { 
      "from": "locations", 
      "localField": "prices.sublocationid", 
      "foreignField": "sublocations._id", 
      "as": "locations" 
     } 
    }, 
    { 
     $unwind: { 
      "path": "$locations" 
     } 
    }, 
    { 
     $unwind: { 
      "path": "$locations.sublocations" 
     } 
    }, 
    { 
     $addFields: { 
      "keep": { 
       "$eq": [ 
        "$prices.sublocationid", 
        "$locations.sublocations._id" 
       ] 
      } 
     } 
    }, 
    { 
     $match: { 
      "keep": true 
     } 
    }, 
    { 
     $addFields: { 
      "price": { 
       "_id": "$prices._id", 
       "sublocationid": "$prices.sublocationid", 
       "sublocation": "$locations.sublocations.sublocation", 
       "price": "$prices.price" 
      } 
     } 
    }, 
    { 
     $group: { 
      "_id": "$_id", 
      "product": { "$first": "$product" }, 
      "prices": { "$addToSet": "$price" } 
     } 
    } 
]); 

それはので、より高いメモリ消費量の、しかし3.6バージョンのように素敵ではありません。

1

以下の集計クエリは3.6バージョンで試すことができます。

ローカルフィールドと外部フィールドの両方が配列なので、等価比較を行うには両方とも$unwindにする必要があります。

このため、新しい$lookup構文を使用する必要があります。

$match$exprは、各製品のサブロケーションIDごとにロケーションのサブロケーションドキュメントを参照するドキュメントフィールド間をコンパイルします。

$project一致するサブロケーションdocを投影する。

$addFields$arrayElemAtを参照して、検索されたサブロケーション配列をドキュメントに変換します。

$group各製品のサブロケーションの文書と一致するすべての価格をプッシュします。

db.products.aggregate[ 
    { 
    "$unwind": "$prices" 
    }, 
    { 
    "$lookup": { 
     "from": "locations", 
     "let": { 
     "prices": "$prices" 
     }, 
     "pipeline": [ 
     { 
      "$unwind": "$sublocations" 
     }, 
     { 
      "$match": { 
      "$expr": [ 
       "$$prices.sublocationid", 
       "$sublocations._id" 
      ] 
      } 
     }, 
     { 
      "$project": { 
      "sublocations": 1, 
      "_id": 0 
      } 
     } 
     ], 
     "as": "prices.sublocations" 
    } 
    }, 
    { 
    "$addFields": { 
     "prices.sublocations": { 
     "$arrayElemAt": [ 
      "$prices.sublocations", 
      0 
     ] 
     } 
    } 
    }, 
    { 
    "$group": { 
     "_id": "$_id", 
     "product": { 
     "$first": "$product" 
     }, 
     "prices": { 
     "$push": "$prices" 
     } 
    } 
    } 
]) 
関連する問題