使用 $lookup 和 let 和管道在 MongoDB 中声明变量

Posted

技术标签:

【中文标题】使用 $lookup 和 let 和管道在 MongoDB 中声明变量【英文标题】:declaring variables in MongoDB using $lookup with let and pipeline 【发布时间】:2019-11-02 09:32:46 【问题描述】:

我正在尝试向我的网站添加 like 功能。我使用以下架构制作了一个 likes 集合。我正在使用自定义 _id 来避免创建额外的索引。


  _id: 
    postId: ObjectId,
    userId: ObjectId
  

我的服务器上有一条使用 MongoDB 聚合 搜索帖子集合的路由。我正在尝试向当前管道添加一个 $lookup 阶段,以便添加一个 liked 属性,其类型为 Boolean 指示是否或用户未喜欢该帖子。这是不工作的 $lookup 阶段(liked 始终返回一个空数组,即使有相应的类似文档):


  $lookup: 
    from: 'likes',
    let:  likedPostId: '$_id.postId', likerUserId: '$_id.userId' ,
    pipeline: [
       $match:
         $expr:
           $and:
            [
               $eq: [
                '$$likerUserId',
                  ObjectId('12345')
              ],
               $eq: [
                  '$$likedPostId',
                  '$_id'
              ]
            ]
          
        
      
    
  ],
  as: 'liked'
  

我认为问题在于 变量 实际上并没有保持我期望的值。有没有办法解决这个问题?另外,如果您知道实现此功能的更简单方法,如果您与我分享,我将不胜感激。

我尝试比较两个相同的 ObjectId() 实例,以确保可以使用 $eq 运算符比较 ObjectId 实例。还尝试在不同的嵌套字段上定义嵌套变量,就像上面代码 sn-p 中的变量一样。这个问题唯一不同的是我试图在 _id 字段之外提取属性。

附:我知道 liked 属性将是一个 Array 而不是 Boolean。但我正在考虑在下一阶段将其转换为 Boolean。但这不是现在的问题。

【问题讨论】:

我认为实现它的更简单方法是在您的帖子模型中添加一个喜欢的字段;这个喜欢的字段将是一组用户 ID。这样您就可以直接查询帖子是否被“点赞”以及被谁点赞。 @FranciscoMarão 我不同意,这种设计模式在大规模 imo 上非常糟糕。 另外@amiratak88 你的语法是正确的,你应该三重检查一个匹配是假设找到的。 @tomslabbaert 感谢您的评论。您能否详细说明一下,尤其是三重检查。 不多说,语法对。我只是仔细检查了我的本地并得到了匹配。这意味着我假设您要匹配的 ID 中的一个不相同。 【参考方案1】:

情况正好相反。如果您在likes 集合上运行$lookup,那么let 部分的目标是定义引用您正在运行聚合的集合的变量。另一方面,您可以使用pipeline 内的单个美元符号来引用likes 集合中定义的字段。试试:


    $lookup: 
        from: 'likes',
        let:  id: '$_id' ,
        pipeline: [
             $match:
                 $expr:
                 $and:
                    [
                     $eq: [
                        '$_id.userId',
                        ObjectId('12345')
                    ],
                     $eq: [
                        '$_id.postId',
                        '$$id'
                    ]
                    ]
                
                
            
        ],
        as: 'liked'
    

编辑:请查看docs

让 可选的。指定要在管道字段阶段中使用的变量。使用变量表达式访问从文档输入到$lookup阶段的字段。

管道无法直接访问输入文档字段。 相反,首先定义输入文档字段的变量,然后 然后引用管道中各个阶段的变量。

【讨论】:

我已经编辑了答案,移动了几美元:)。这就是你的建议吗?我已经尝试过这种想法,也许我无法在 let 中提取变量,而是在我想使用它们时将它们拉出。仍然没有运气:( 在使用 _id 以外的字段时,任何一种方式都可以使用 @Amiratak88 我刚刚拒绝了您的编辑。问题是你应该反过来使用 $lookup 。正如文档所说, let 用于输入集合,而不是 from 语句定义的集合 您能否详细说明一下反过来?你的意思是改变 from 属性? @Amiratak88 gotcha,批准您的编辑,感谢您接受答案:)

以上是关于使用 $lookup 和 let 和管道在 MongoDB 中声明变量的主要内容,如果未能解决你的问题,请参考以下文章

使用管道中的数组中的对象值执行 $lookup

$lookup 中的其他连接条件严重降低了性能(使用管道)

MongoDB 聚合 $lookup 到具有管道语法和 _id 作为字符串的父数组字段

基于通过 $lookup 检索的字段的多阶段聚合管道匹配数据

Mongodb 聚合管道限制 $lookup 字段

MongoDB——聚合管道之$lookup操作