$lookup when foreign field is an array

2020-07-20 04:07发布

问题:

I have two collections.

Sports:

{
    "_id" : ObjectId("5bcaf82120e047301b443c06"),
    "item_name" : "Football",
    "item_icon" : "ps_icon_football.png", 
    "slot_divisions" : {
    "0" : {
        "div_id" : ObjectId("5bd037ec5021b307e793f7b3"),
        "description" : "5x5"
    },
    "1" : {
        "div_id" : ObjectId("5bd0384b5021b307e793f7b4"),
        "description" : "7x7"
    }
 })

Booking:

{
    "_id" : ObjectId("5be015bd870565038c7660f4"),
    "spot" : ObjectId("5bd825cb8705651b1c2f17e2"),
    "date" : ISODate("2018-11-13T10:04:45.000Z"),
    "slots" : [ 
        {
            "booking_id" : ObjectId("5be015bd870565038c7660f3"),
            "slot_id" : ObjectId("5bd0384b5021b307e793f7b4"),
             ...
        }]
}

I want to show the booking details. While joining two collections, sport details cannot be fetched.

I tried this:

     $bookData  =   Booking::raw(function($collection) use($request) {
                   ....
            return $collection->aggregate([
               ['$lookup' => ['from'=>'spots', 'localField'=>'spot_id', 'foreignField'=>'_id', 'as'=>'spot_data']],
               ['$lookup' => ['from'=>'sports_items', 'localField'=>'slots.slot_id', 'foreignField'=>'slot_divisions.div_id', 'as'=>'sports_data']],
               ['$unwind'  =>'$slots'],
               ['$project' => [
                    'booking_id'=>'$slots.booking_id',
                    'date'=>'$date',
                    'sports_data.item_name'=>'$sports_data.item_name',
                    'sports_data.item_icon'=>'$sports_data.item_icon',
                ]],

            ]);
        });

Im getting the response:

"sports_data": []

Can someone help me with this?

Update : I tried pipe lining in look up as follows. But still empty result

 ['$lookup' => ['from'=>'sports_items', 'localField'=>'slots.slot_id', 'foreignField'=>'slot_divisions.div_id', 'as'=>'sports_data']],   

changed to

      ['$lookup' => [
                    'from'=>'sports_items_collection',
                     'pipeline' =>[
                         ['$unwind'  =>'$slot_divisions'],
                         ['$match'=>["slots.slot_id"=>['$eq'=> ["slot_divisions.div_id"]]]]
                     ],
                     'as'=>'sports_data'
                   ]],

My expected output is:

  "booking": [
        {
            "booking_id": "5be015bd870565038c7660f3",
            "date": "2018-11-13 15:34:45",
            "sports_data": [
        "item_name" : "Football",
        "item_icon" : "ps_icon_football.png", 
        ]
        },

回答1:

You can use below aggregation

You can use new $lookup syntax to $unwind the foreign array inside the $lookup pipeline and then can easily $match with ids

db.bookings.aggregate([
  { "$lookup": {
    "from": "sports",
    "let": { "slot_id": "$slots.slot_id" },
    "pipeline": [
      { "$unwind": "$slot_divisions" },
      { "$match": { "$expr": { "$in": ["$slot_divisions.div_id", "$$slot_id"] }}},
      { "$project": { "item_name": 1, "item_icon": 1 }}
    ],
    "as": "sports_data"
  }},
  { "$project": {
    "booking_id": { "$arrayElemAt": ["$slots.booking_id", 0] },
    "date": 1,
    "sports_data": 1
  }}
])