【问题标题】:How to join three collections without $unwind and get nested result based on a condition?如何在没有 $unwind 的情况下加入三个集合并根据条件获取嵌套结果?
【发布时间】:2020-08-21 16:23:44
【问题描述】:

人物集合:

[
  {
    "_id": ObjectId("5f3258cfbaaccedaa5dd2c96"),
    "gender": "male",
    "name": {
      "title": "mr",
      "first": "victor",
      "last": "pedersen"
    },
    "location": {
      "street": "2156 stenbjergvej",
      "city": "billum",
      "state": "nordjylland",
      "postcode": 56649        
    },
    "email": "victor.pedersen@example.com"
  }
]

PersonDetails 集合:

{
    "_id": ObjectId("5f3a91e68b1c26e68f9ed3ad"),
    "country": "India",
    "personid": ObjectId("5f3258cfbaaccedaa5dd2c96")
}

CountryDetails 集合:

{
    "_id": ObjectId("5f3fc2aa9532398a037ff7ae"),
    "country": "India",
    "continent": "Asia"
}

假设 1 个人可以有很多个人信息,而 1 个人信息可以有很多国家信息。

查询:获取大洲为亚洲的 Person、persondetails 和 countrydetails。

结果应该是这样的:

[{
    "_id": ObjectId("5f3258cfbaaccedaa5dd2c96"),
    "gender": "male",
    "name": {
        "title": "mr",
        "first": "victor",
        "last": "pedersen"
    },
    "location": {
        "street": "2156 stenbjergvej",
        "city": "billum",
        "state": "nordjylland",
        "postcode": 56649
    },
    "email": "victor.pedersen@example.com",
    "persondetail": [{
        "_id": ObjectId("5f3a91e68b1c26e68f9ed3ad"),
        "country": "India",
        "personid": "5f3258cfbaaccedaa5dd2c96",
        "countrydetail": [{
            "_id": ObjectId("5f3fc2aa9532398a037ff7ae"),
            "country": "India",
            "continent": "Asia"
        }]
    }]
}]

注意:这必须使用 aggregate()

我的失败尝试:

db.persons.aggregate([
  {
    "$match": {
      "$expr": {
        "$eq": [
          "$_id",
          {
            "$toObjectId": "5f3258cfbaaccedaa5dd2c96"
          }
        ]
      }
    }
  },
  {
    $lookup: {
      from: "persondetails",
      localField: "_id",
      foreignField: "personid",
      as: "persondetail"
    }
  },
  {
    $unwind: {
      "path": "$persondetail",
      includeArrayIndex: "arrayIndex",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "country",
      localField: "persondetail.country",
      foreignField: "country",
      as: "countrydetails"
    }
  },
  {
    "$match": {
      "$expr": {
        "$eq": [
          "$persondetail.continent",
          "Asia"
        ]
      }
    }
  }
])
 

上面的查询不起作用,即使它可以工作unwind 也会给我一个扁平的结构。这与我正在寻找的相反。

【问题讨论】:

    标签: node.js mongodb mongodb-query nosql aggregation-framework


    【解决方案1】:

    您可以使用 $lookup with custom pipeline 嵌套查找:

    {
        $lookup: {
           from: "persondetails",
           let: { person_id: "$_id" },
           pipeline: [
               {
                   $match: {
                       $expr: { $eq: [ "$personid", "$$person_id" ] }
                   }
               },
               {
                   $lookup: {
                       from: "countrydetails",
                       localField: "country",
                       foreignField: "country",
                       as: "countrydetail",
                   }
               }
           ],      
           as: "persondetail"
        }
    }
    

    Mongo Playground

    【讨论】:

    • 太棒了。不过,我确实有几个问题。 1. let: { person_id: "$_id" } 这里的$_id 指的是什么? 2. 可以在不创建person_id 变量的情况下重写吗? (由于难以在评论中解释的原因,我的查询中不能包含变量)
    • No 目前似乎没有替代变量
    • 不错的解决方案!
    • @SamuraiJack 这指的是来自person 集合的_id。你的 MongoDB 版本是多少?
    • @mickl 4.2,可以使用最新的。
    猜你喜欢
    • 2020-05-16
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多