【问题标题】:$lookup for each element within a sub-array$lookup 查找子数组中的每个元素
【发布时间】:2019-07-10 07:15:46
【问题描述】:

所以在我的数据库中,我有 3 个集合,它们看起来像这样:

客户:

customers = [
  {_id: 1, username: "jack", ... },
  {_id: 2, username: "jane", ... }
  ...
]

评论:

reviews = [
  { _id: 1, customerID: 1, message: "my message", ...}
  ...
]

评论:

comments = [
  { _id: 1, reviewID: 1, customerID: 2, message: "my response" ...}
  ...
]

客户可以发表评论,也可以评论其他评论。 所以,我想要的是一个 mongodb aggregation 查询:

  1. 检索评论。

  2. 进行评论的客户的数据。

  3. 该评论中的 cmets。

  4. 对该评论发表评论的客户的数据。

reviews = [
  {
    _id: 1,
    username: "jack",
    message: "my message"
    comments: [
      { _id: 1, username: "jane", message: "my response", ...},
      ...
    ]
    ...
  }
  ...
]

【问题讨论】:

  • 我知道这不是您要问的,但是您正在以一种真正的关系(即不是 mongo 友好)方式构建数据,这就是为什么您遇到问题的原因唯一的解决方案是为看起来像普通查询的两个$lookups。解决这个问题的更标准的 mongo-y 方法是拥有一个 reviews 集合,该集合看起来类似于您的最终输出,在 cmets 数组中的 cmets 上有非规范化的用户名

标签: node.js mongodb mongoose aggregation-framework


【解决方案1】:

您可以从comments 集合和$lookupcustomers 开始获取customer 名称,然后您可以$group all cmets by review 和$lookup 两次(reviewscustomer )。每次您知道这是一对一的关系时,您都可以在$lookup 之后使用$unwind。试试:

db.comments.aggregate([
    {
        $lookup: {
            from: "customers",
            localField: "customerID",
            foreignField: "_id",
            as: "customer"
        }
    },
    {
        $unwind: "$customer"
    },
    {
        $project: {
            _id: 1,
            reviewID: 1,
            username: "$customer.username",
            message: 1
        }
    },
    {
        $group: {
            _id: "$reviewID",
            comments: { $push: { _id: "$_id", username: "$username", message: "$message" } }
        }
    },
    {
        $lookup: {
            from: "reviews",
            localField: "_id",
            foreignField: "_id",
            as: "review"
        }
    },
    {
        $unwind: "$review"
    },
    {
        $lookup: {
            from: "customers",
            localField: "review.customerID",
            foreignField: "_id",
            as: "customer"
        }
    },
    {
        $unwind: "$customer"
    },
    {
        $project: {
            _id: 1,
            message: "$review.message",
            username: "$customer.username",
            comments: 1
        }
    }
])

输出:

{ "_id" : 1, "comments" : [ { "_id" : 1, "username" : "jane", "message" : "my response" } ], "message" : "my message", "username" : "jack" }

编辑: 如果您想从reviews 开始并将其过滤为单个电影,则可以使用$lookup with custom pipeline

db.reviews.aggregate([
    {
        $match: {
            movieId: 1,
        }
    },
    {
        $lookup: {
            from: "customers",
            localField: "customerID",
            foreignField: "_id",
            as: "customer"
        }
    },
    {
        $unwind: "$customer"
    },
    {
        $lookup: {
            from: "comments",
            let: { reviewId: "$_id" },
            pipeline: [
                {
                    $match: { $expr: { $eq: [ "$$reviewId", "$reviewID" ] } }
                },
                {
                    $lookup: {
                        from: "customers",
                        localField: "customerID",
                        foreignField: "_id",
                        as: "customer"
                    }
                },
                {
                    $unwind: "$customer"
                },
                {
                    $project: {
                        _id: 1,
                        message: 1,
                        username: "$customer.username"
                    }
                }
            ],
            as: "comments"
        }
    },
    {
        $project: {
            _id: 1,
            message: 1,
            username: "$customer.username",
            comments: 1
        }
    }
])

带来相同的输出

【讨论】:

  • 这不会返回评论者的用户名
  • @KingsleyKbcComics 是的,现在应该没问题
  • 谢谢,但我也不能从 cmets 开始。评论还有一个movieID 字段,这是我发出http 请求时输入的键。
  • 但你的问题中没有提到它:)
  • 我知道,很抱歉。但我把我想要的结果说成"reviews = ..."
【解决方案2】:

您可以将以下聚合与 mongodb 3.6 及更高版本一起使用

Reviews.aggregate([
  { "$lookup": {
    "from": Customers.collection.name,
    "let": { "customerID": "$customerID" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$_id", "$$customerID"] } } }
    ],
    "as": "customer"
  }},
  { "$unwind": "$customer" },
  { "$lookup": {
    "from": Comments.collection.name,
    "let": { "reviewID": "$_id" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$reviewID", "$$reviewID"] } } },
      { "$lookup": {
        "from": Customers.collection.name,
        "let": { "customerID": "$customerID" },
        "pipeline": [
          { "$match": { "$expr": { "$eq": ["$_id", "$$customerID"] } } }
        ],
        "as": "customer"
      }},
      { "$unwind": "$customer" },
    ],
    "as": "comments"
  }}
])

【讨论】:

    猜你喜欢
    • 2019-02-02
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    相关资源
    最近更新 更多