【问题标题】:How to $lookup in nested array of objects如何在嵌套的对象数组中查找 $lookup
【发布时间】:2020-08-10 13:12:53
【问题描述】:

我必须有两个集合,一个是旅游,另一个是目的地,所以在旅游中,我有一个位置数组,其中有一个带有 id 的目标对象,并且该 id 属于另一个目的地集合,但问题是我不能在位置数组中查找目的地的详细信息。每一个在这里也尝试了很多查询搜索。但没有得到预期的结果。

游览:

{
    "_id" : ObjectId("5f3122f4d8d57e3b9650e5b4"),
    "title" : "tour 1",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ec5ae9037ea99f20a79071a"
            },
            "services" : {
                "hotel" : true
            }
        }, 
        {
            "destination" : {
                "id" : "5ec5ae8e37ea99f20a78ef8c"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
}
{
    "_id" : ObjectId("5f2d65e68bc6e9155310d147"),
    "title" : "tour 2",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ecf994435c3a6025d5bf126"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
}
{
    "_id" : ObjectId("5f2d66398bc6e9155310d161"),
    "title" : "tour 3",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ec5ae8e37ea99f20a78ef8d"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
}

目的地:

{
    "_id" : ObjectId("5ec5ae9037ea99f20a79071a"),
    "name" : "dest 1",
    "country" : "country name"
}
{
    "_id" : ObjectId("5ec5ae8e37ea99f20a78ef8c"),
    "name" : "dest 2",
    "country" : "country name"
}
{
    "_id" : ObjectId("5ec5ae8e37ea99f20a78ef8d"),
    "name" : "dest 3",
    "country" : "country name"
}
{
    "_id" : ObjectId("5ecf994435c3a6025d5bf126"),
    "name" : "dest 4",
    "country" : "country name"
}

预期结果:

{
    "_id" : ObjectId("5f3122f4d8d57e3b9650e5b4"),
    "title" : "tour 1",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ec5ae9037ea99f20a79071a",
                "name" : "dest 1",
                "country" : "country name"
            },
            "services" : {
                "hotel" : true
            }
        }, 
        {
            "destination" : {
                "id" : "5ec5ae8e37ea99f20a78ef8c",
                "name" : "dest 2",
                "country" : "country name"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
},
{
    "_id" : ObjectId("5f2d65e68bc6e9155310d147"),
    "title" : "tour 2",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ecf994435c3a6025d5bf126",
                "name" : "dest 4",
                "country" : "country name"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
},
{
    "_id" : ObjectId("5f2d66398bc6e9155310d161"),
    "title" : "tour 3",
    "locations" : [ 
        {
            "destination" : {
                "id" : "5ec5ae8e37ea99f20a78ef8d",
                "name" : "dest 3",
                "country" : "country name"
            },
            "services" : {
                "hotel" : true
            }
        }
    ]
}

尝试查询:

db.tours.aggregate([
  { 
    "$addFields": {
      "locations": {
        "$map": {
          "input": "$locations",
          "in": {
            "$mergeObjects": [
              "$$this",
              {
                "dest_oid": {
                  "$toObjectId": "$$this.destination.id"
                }
              }
            ]
          }
        }
      }
    }
  },
  { "$unwind": "$locations" },

  { "$lookup": {
    "from": "destinations",
    "localField": "locations.dest_oid",
    "foreignField": "_id",
    "as": "locations.dest",
  }},
  { "$unwind": "$locations.dest" },
  { "$group": {
    "_id": "$_id",
    "locations": { "$push": "$locations" }
  }}
])

即使我试过这个 MongoDB $lookup on nested document

【问题讨论】:

  • 您是否已通过接受的答案完美地检查了您的预期结果?看看destination 被合并到一个数组中并且services 在特定的destination 对象之外?请完美检查。是你想要的吗?
  • 是的,你是对的,这不是答案。
  • 那么你检查过我的答案了吗?

标签: mongodb mongoose mongodb-query


【解决方案1】:

快速修复,

  • $unwind locations 数组放在第一位,因为需要将 id 转换为对象 id
db.tours.aggregate([
  { $unwind: "$locations" },
  • 如果你已经转换了字符串 id t 对象 id,你可以跳过这部分
  • $addFields 替换 locations.destination.id 到对象 id 将您的逻辑过滤为短,这里不需要 $map 和 $mergeObjects 选项
  {
    $addFields: {
      "locations.destination.id": {
        $toObjectId: "$locations.destination.id"
      }
    }
  },
  • $lookup 你已经这样做了,但更改为 locations.destination
  {
    $lookup: {
      from: "destinations",
      as: "locations.destination",
      localField: "locations.destination.id",
      foreignField: "_id"
    }
  },
  • $unwind locations.destination 因为它的数组和我们需要对象
  {
    $unwind: {
      path: "$locations.destination"
    }
  },
  • $group 你已经做了,很少的变化,在位置推送第一个目的地和服务并添加第一个标题
  {
    $group: {
      _id: "$_id",
      locations: { $push: "$locations" },
      title: { $first: "$title" }
    }
  }
])

游乐场:https://mongoplayground.net/p/yaTCij7NRUj

【讨论】:

  • 这是给Unrecognized expression '$first'
  • mongodb 4.2版
  • 使用shell进行测试,必须在mongoose中使用
  • 我已将字符串转换为 objectId()
  • 好的,因为 $first 在 4.2 版本的 $push 中不支持,所以只需要为此添加另一个管道,将添加,如果您已转换则无需使用 $addFields管道,我正在更新我的答案。
【解决方案2】:

如果您可以将Tours 集合中的string destination.id 转换/更新为ObjectId(如果还没有的话)。以下查询应该可以工作。

查询:

db.Tours.aggregate([
  {
    $unwind: "$locations",
  },
  {
    $lookup: {
      from: "Destinations",
      localField: "locations.destination.id",
      foreignField: "_id",
      as: "destination",
    },
  },
  {
    $project: {
      title: "$title",
      locations: {
        destination: {
          $arrayElemAt: ["$destination", 0],
        },
        services: "$locations.services",
      },
    },
  },
  {
    $group: {
      _id: "$_id",
      title: {
        $first: "$title",
      },
      locations: {
        $push: "$locations",
      },
    },
  },
]);

Playground Link

【讨论】:

  • 有什么快速的方法可以将字符串转换为 ObjectId 还是我必须执行 forEach 才能更新?
  • @VijayKumar 更新了答案,以防您对备用查询感兴趣。此外,由于您提到已将 destination.id 从字符串更新为 ObjectId。我还没有进入转换阶段。
  • 如果位置没有对象会发生什么,它仍然会给出结果吗?或destination.id 为空
  • 如果destination.id = null 则可以正常工作,但如果没有位置,则无法正常工作。 ref
  • 编辑:unwind 就是这样工作的。如果位置没有对象[],您将因为$unwind 而丢失该特定文档。如果它是null,最终位置数组将不包含它,但会保留其他属性,即services。此外,将这些案例包括在问题本身中以更好地理解也是一个好主意。如果没有位置,是否要保留文档。
猜你喜欢
  • 2018-11-30
  • 2021-08-09
  • 2015-02-12
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
  • 2017-12-24
  • 1970-01-01
相关资源
最近更新 更多