首页 > 解决方案 > 在 mongodb 中使用 $lookup 进行聚合左连接

问题描述

我有三个收藏

posts=[
{
    "id": "p1",
    "title": "title 1"
},
{
    "id": "p2",
    "title": "title 2"
}]
users = [
{
    "id": "u1",
    "name": "name1"
},
{
    "id": "u2",
    "name": "name2"
}]
comments = [
{
    "userId": "u1",
    "postId": "p1",
    "comment": "comment 1"
}]

我想通过 userId(u1) 获取每个帖子中的所有收藏帖子和评论:

posts=[
{
    "id": "p1",
    "title": "title 1",
    "comments":[
        "userId": "u1",
        "comment": "comment 1"
    ]
},
{
    "id": "p2",
    "title": "title 2",
    "comments":[]
}]

我使用了聚合函数和 $lookup 运算符,但我不知道使用 $match 运算符来过滤 userId。我在下面使用了聚合:

self.db.posts.aggregate([                
            {
                "$lookup":{
                    "from": "comments",
                    "localField": "id",
                    "foreignField": "postId",
                    "as": "comments",                        
                }
            },                
            {
              "$match":{
                  "comments.userId": {"$eq": param.objectUserId}
              },
            },
            {"$skip": (param.page - 1) * param.pageSize},
            {"$limit": param.pageSize},
            {"$sort": {"unixDate": pymongo.DESCENDING}}
        ])

它只返回与 userId="u1" 对应的数组中的一篇文章

请帮我!谢谢大家!

标签: mongodb-query

解决方案


您必须使用阶段pipeline选项$lookup并通过您要申请的附加条件。

db.posts.aggregate([
  {
    "$lookup": {
      "from": "comments",
      "let": {
        "pId": "$id"
      },
      "pipeline": [
        {
          "$match": {
            "$expr": {
              "$eq": [
                "$postId",
                "$$pId"
              ],
            },
            "userId": "u1",
          },
        },
        {
          "$project": {
            "_id": 0,
            "userId": 1,
            "comment": 1,
          },
        },
      ],
      "as": "comments"
    }
  }
])

Mongo Playground 示例执行

self.db.posts.aggregate([                
    {
    "$lookup": {
      "from": "comments",
      "let": {
        "pId": "$id"
      },
      "pipeline": [
        {
          "$match": {
            "$expr": {
              "$eq": [
                "$postId",
                "$$pId"
              ],
            },
            "userId": param.objectUserId,
          },
        },
        {
          "$project": {
            "_id": 0,
            "userId": 1,
            "comment": 1,
          },
        },
      ],
      "as": "comments"
    }
  },
    {"$skip": (param.page - 1) * param.pageSize},
    {"$limit": param.pageSize},
    {"$sort": {"unixDate": pymongo.DESCENDING}}
])

推荐阅读