【问题标题】:MongoDB - Aggregation on referenced fieldMongoDB - 引用字段的聚合
【发布时间】:2023-03-22 18:45:01
【问题描述】:

我有一个关于文档设计的问题,以便能够有效地执行聚合。我将举一个文档的虚拟示例:

{
   product: "Name of the product",
   description: "A new product",
   comments: [ObjectId(xxxxx), ObjectId(yyyy),....]
}

如您所见,我有一个简单的文档,它描述了一种产品并在其上包装了一些 cmets。想象一下这个产品非常受欢迎,以至于它包含数百万个 cmets。评论是一个简单的文档,带有日期、文本以及最终的一些其他特征。问题是这样的产品很容易大于 16MB,所以我不需要在产品中嵌入 cmets,而是在单独的集合中。

我现在想做的是对产品集合执行聚合,例如,第一步可以是选择各种产品并按日期对 cme​​ts 进行排序。嵌入文档是一个非常简单的操作,但我怎么能用这样的设计呢?我只有 cmets 的 ObjectId 而不是它们的内容。当然,我希望在单个操作中执行此聚合,即我不希望必须执行聚合的第一部分,然后查询结果并执行另一个聚合。

我不知道这是否足够清楚? ^^

【问题讨论】:

  • 您能否提供一些您期望的真实样本数据和输出?
  • 恐怕不行。这更像是一个概念性问题,但我认为给定的示例文档是一个很好的开始示例。问题是在使用 MongoDB 进行聚合时如何处理引用的文档。答案通常是嵌入参考文档,但如果由于大小限制而无法实现呢?
  • 对于您的示例,您只需在评论集合中的 product 字段上进行选择,然后进行排序 - 它甚至不需要聚合。如果要获取产品文档和评论文档,需要进行应用级join。我会搜索 cmets,然后解析产品参考,而不是相反。无法在一次操作中从多个集合中获取信息。

标签: mongodb aggregation-framework


【解决方案1】:

我会这样做:创建一个临时集合,它是产品集合的精确副本,唯一的例外是 cmets 数组上架构的更改,它将被修改为包含一个注释对象而不是对象标识。评论对象将只有 _id 和日期字段。以上可以一步完成:

var comments = [];
db.product.find().forEach( function (doc){
    doc.comments.forEach( function(x) {
        var obj = {"_id": x };
        var comment = db.comment.findOne(obj);
        obj["date"] = comment.date;
        comments.push(obj);
    });
    doc.comments = comments;
    db.temp.insert(doc);
});

然后您可以针对临时集合运行聚合查询:

db.temp.aggregate([
    {
        $match: {
            // your match query
        }
    },
    {
        $unwind: "$comments"
    },    
    {
        $sort: { "comments.date": 1 } // sort the pipeline by comments date
    }
]);

【讨论】:

  • 感谢您的建议。我可以得出的结论是,不可能一步完成。必须更改架构,否则我们必须使用适合我们想要进行的聚合的临时文档。我希望这是可能的,但恐怕不是:(
猜你喜欢
  • 1970-01-01
  • 2019-06-17
  • 2019-01-17
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 2023-01-04
  • 2021-08-01
  • 1970-01-01
相关资源
最近更新 更多