首页 > 解决方案 > $lookup 与深度嵌套的对象

问题描述

我是 MongoDB 的新手,目前正在为学校开发一个建议饮食计划的食谱应用程序。因此,我需要将用户饮食计划中的“膳食”ObjectId(“用户”集合)与“膳食”集合中的 ObjectId 结合起来。

之后,我需要在“Meals”集合中加入一个“ingredient”ObjectID,并在“Ingredients”集合中加入“ingredient”的ID。问题是,集合“Meals”中的“成分”ObjectID 位于具有另一个整数变量“amount”的对象中。该对象嵌套在一个称为“成分”的数组中,其中包含许多对象,例如刚刚描述的对象。

以下是我的结构:

用户

{
 "_id": ObjectId("5b28cab902f28e18b863bd36"),
 "username: "testUser1",
 "password": "$2a$08$KjddpaSQPjp6aF/gseOhVeddYdqWJCJ4DpFwxfNgsk81G.0TOtN5i",
 "dietPlans": Object
    {
     "dietPlanCurrent":Object
         {
          "monday":Object
               {
               "breakfast":Object
                    {
                     "meal": ObjectId("5b2b9a8bbda339352cc39ec4")
                 },
                 … 
           },
           … 
     },
     …
  },
}

膳食

{
   "_id" : ObjectId("5b2b9a8bbda339352cc39ec4"),
   "name": "Gulasch-breakfast",
   "cuisine": "International",
   "ingredients":[
       {
            "ingredient": ObjectId("5b1ec0f939b55efcd4e28a2d"),
            "amount": 20
       },
       {
            "ingredient": ObjectId("5b1ec42474fc1f58d84264d4"),
            "amount": 20
       },
       {
            "ingredient": ObjectId("5b1ec42474fc1f58d84264d5"),
            "amount": 20
       },
       …   
    ],

   "comments": [
        …
    ]
}

原料

{ 
    {
     "_id": ObjectId("5b1ec0f939b55efcd4e28a2d"),
     "name": "Walnut",
     "calories": 654
      … 
    }
    {
     "_id": ObjectId("5b1ec0f939b55efcd4e28a3d"),
     "name": "Apple",
     "calories": 123
     … 
    }
… 
}

我想要得到的是:

    {
 "_id": ObjectId("5b28cab902f28e18b863bd36"),
 "username: "testUser1",
 "password": "$2a$08$KjddpaSQPjp6aF/gseOhVeddYdqWJCJ4DpFwxfNgsk81G.0TOtN5i",
 "dietPlans": Object
    {
     "dietPlanCurrent":Object
         {
          "Monday":Object
               {
               "breakfast":Object
                    {
                     "meal": ObjectId("5b2b9a8bbda339352cc39ec4")
                     "matchedIngredients": [
                        {
                         "_id": ObjectId("5b1ec0f939b55efcd4e28a2d"),
                         "name": "Walnut",
                         "calories": 654
                         … 
                        }
                      … 
                      ]

                 },


                 … 
           },


           … 
     },
     …
  },
}

我的方法不起作用(仅返回空的matchedIngredients Array)

    {
        $match: {
            '_id': mongoose.Types.ObjectId(req.params.userId)
        }
    },
    {
        $lookup:   {
            from: 'meals',
            localField: 'dietPlans.dietPlanCurrent.monday.breakfast.meal',
            foreignField: '_id',
            as: "dietPlans.dietPlanCurrent.monday.breakfast.mealObject"
        }              
    },
    {
        $unwind: {
            path: "$dietPlans.dietPlanCurrent.monday.breakfast.mealObject",
            preserveNullAndEmptyArrays: true
        }
    },
   {
        $unwind: {
               path: "$dietPlans.dietPlanCurrent.monday.breakfast.mealObject.ingredients",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $lookup:   {
            from: 'ingredients',
            localField: 'dietPlans.dietPlanCurrent.monday.breakfast.mealObject.ingredients.ingredient',
            foreignField: '_id',
            as: "dietPlans.dietPlanCurrent.monday.breakfast.matchedIngredients"
        }              
    }

非常感谢您的帮助。我已经检查了这种方法,但不知何故它不起作用:

对我不起作用的方法

非常感谢你!

标签: javascriptarraysmongodblookupaggregation

解决方案


mongodb 3.4版无法执行您尝试做的事情,但如果您升级到3.6,那么您可以尝试以下聚合

db.collection.aggregate([
  { "$match": { "_id": mongoose.Types.ObjectId(req.params.userId) } },
  { "$lookup": {
    "from": Meals.collection.name,
    "let": { "meal_id": "$dietPlans.dietPlanCurrent.monday.breakfast.meal" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$_id", "$$meal_id" ] } } },
      { "$unwind": "$ingredients" },
      { "$lookup": {
        "from": Ingredients.collection.name,
        "let": { "ingredient_id": "$ingredients.ingredient" },
        "pipeline": [
          { "$match": { "$expr": { "$eq": [ "$_id", "$$ingredient_id" ] } } }
        ],
        "as": "matchedIngredients"
      }},
      { "$unwind": "$ingredients.matchedIngredients" },
      { "$group": {
        "_id": "$_id",
        "name": { "$first":"$name" },
        "cuisine": { "$first":"$cuisine" },
        "ingredients": { "$push":"$ingredients" }
      }}
    ],
    "as": "dietPlans.dietPlanCurrent.monday.breakfast.mealObject"
  }},
  { "$unwind": "$dietPlans.dietPlanCurrent.monday.breakfast.mealObject" }
])

推荐阅读