$lookup 嵌套文档

Posted

技术标签:

【中文标题】$lookup 嵌套文档【英文标题】:$lookup with nested documents 【发布时间】:2019-04-29 02:55:23 【问题描述】:

我需要加入/查找三个集合。 “团体” “用户” “链接标签” “照片”

我正在从集合组中获取所有组。

group 
    id: 1,
    start: 10.12,
    linkedUsers : [1,2,3,4,5]

然后我需要从用户那里查找/加入

user 
    id: 1,
    name: ""

然后从linkedTags

tag 
    userId: 1,
    rounds: 3,
    time: 180

然后从“照片”

photo 
    userId: 1,
    location: ""

所以我需要这样:

Group 
    id: 1,
    start: 10.12,
    linkedUsers: [1,2,3,4],
    users: [
        1:
            id: 1,
            name: "",
            rounds: 3,
            time: 180,
            photos: [
                1: 
                    id: 1,
                    location: ""
                
            ]
        
    ]

这是我迄今为止尝试过的。我认为我需要分阶段进行,但我还没有弄清楚如何去做。

  db('groups').aggregate([
    
      $lookup: 
        from: 'users',
        localField: 'linkedUsers',
        foreignField: 'id',
        as: 'users'
      
    ,
    
      $unwind: "$users"
    ,
    
      $lookup: 
        from: 'photos',
        localField: 'linkedUsers',
        foreignField: 'id',
        as: 'photos'
      
    ,
    
      $unwind: "$photos"
    ,
    
      $lookup: 
        from: 'linkedTags',
        localField: 'linkedUsers',
        foreignField: 'id',
        as: 'tags'
      
    ,
    
      $unwind: "$tags"
    ,
     $group: 
        _id: null,
        id: "$id",
        start: '$start',
        linkedUsers: "$linkedUsers",
        users: $push: 
          id: "$users.id",
          name: "$users.name",
          rounds: "$tags.rounds",
          time: "$tags.time",
          photos: $push: 
            id: "$photos.id",
            location: "photos.location"
          
        
    
  ])

编辑 1: 这是我遇到的第一个错误:

MongoError: 字段 'id' 必须是累加器对象

我已经阅读了该内容,但我不明白它们是如何组合在一起的。

编辑 2: 我通过将分组包装在 _id 中解决了这个问题:

现在我遇到无法识别的表达式'$push'

编辑 3: 在 Atlas、4.0.4 Enterprise 上运行。

【问题讨论】:

对我来说一切都很好。有什么问题? 我得到的第一个错误是:“MongoError: The field 'id' must be an accumulator object” 我已经更新了我的问题以包含这个。 我修复了将整个组包装在 _id 中的问题: 现在我得到“MongoError: Unrecognized expression '$push'” 仅使用photos: $photos 放上你使用的mongodb版本会更好 【参考方案1】:

你可以使用下面的聚合

db.group.aggregate([
   "$lookup": 
    "from": "users",
    "let":  "linkedUsers": "$linkedUsers" ,
    "pipeline": [
       "$match":  "$expr":  "$in": ["$_id", "$$linkedUsers"]   ,
       "$lookup": 
        "from": "tags",
        "let":  "userId": "$_id" ,
        "pipeline": [
           "$match":  "$expr":  "$eq": ["$userId", "$$userId"]   
        ],
        "as": "tags"
      ,
       "$lookup": 
        "from": "photos",
        "let":  "userId": "$_id" ,
        "pipeline": [
           "$match":  "$expr":  "$eq": ["$userId", "$$userId"]   
        ],
        "as": "photos"
      
    ],
    "as": "linkedUsers"
  
])

编辑:删除变量中的空格

【讨论】:

优秀。我已经开始研究一些放松的团体解决方案。但是这个 IMO 是一个更好的解决方案。一旦我删除了您在变量中留下的一些无意的空格,它就像一个魅力一样工作。【参考方案2】:

我已尝试创建一个示例关系转储数据

检查工作示例here

尝试按_id 分组,然后分配photos: $photos

二级$push 是您的问题。

db.groups.aggregate([
  
    $unwind: "$linkedUsers"
  ,
  
    $lookup: 
      from: "users",
      localField: "linkedUsers",
      foreignField: "_id",
      as: "users"
    
  ,
  
    $unwind: "$users"
  ,
  
    $lookup: 
      from: "photos",
      localField: "linkedUsers",
      foreignField: "userId",
      as: "photos"
    
  ,
  
    $unwind: "$photos"
  ,
  
    $lookup: 
      from: "tags",
      localField: "linkedUsers",
      foreignField: "userId",
      as: "tags"
    
  ,
  
    $unwind: "$tags"
  ,
  
    $group: 
      _id: "$_id",
      "start": 
        $first: "$start"
      ,
      "linkedUsers": 
        $first: "$linkedUsers"
      ,
      "users": 
        "$push": 
          "id": "$users._id",
          "name": "$users.name",
          "rounds": "$tags.rounds",
          "time": "$tags.time",
          "photos": "$photos"
        
      
    
  
])

由于我已经创建了手动数据,您可能需要对您的实现进行一些键或数据库名称更改。


注意:-

我建议在使用多级$unwind 时使用preserveNullAndEmptyArrays。如果没有找到内部级别,您可以通过它来提供原始文档。

 $unwind:  path: "$tags", preserveNullAndEmptyArrays: true   

希望对您有所帮助。

【讨论】:

非常感谢!这真的帮助了我在这个几乎相同但不完全一样的问题和答案的丛林中。试图拼凑一些对我有用的东西。 我以为我可以自己整理其余部分。但三个小时后,我仍然不聪明。我已经更新了您的工作示例以适合我的数据库。如您所见,如果有多张照片,您会为每张照片获得一个用户:mongoplayground.net/p/30wCJjcICZg 请告知。

以上是关于$lookup 嵌套文档的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB $lookup 在 2 级嵌套文档上不使用 $unwind

MongoDB $lookup 在 2 级嵌套文档上不使用 $unwind

在查找操作之后隐藏嵌套文档中的_id

$lookup 嵌套对象数组

$lookup 嵌套对象数组

MongoDb:使用 $lookup 查找深度嵌套的对象