【问题标题】:MongoDB multiple $lookup and $group outputMongoDB 多个 $lookup 和 $group 输出
【发布时间】:2021-04-27 00:45:17
【问题描述】:

我是 MongoDB 的新手,我正在尝试基于两个相关集合和第三个集合检索一种排行榜,根据其不同的属性引用这两个集合中的一个。

Schema can be found here

考虑如下架构:

tree: { _id, company_id: string, company_name }
link: { _id, company_id: string, url: string }
analytics: { _id, tree_id: string, link_id: string, views: number, clicks: number, date: string }

analytics 文档可以同时包含 tree_id, viewslink_id, clicks
我现在想要实现的是总点击次数+观看次数的一种“排行榜”,从analytics集合开始,与treelink一起加入,最后检索总和点击次数和观看次数。
我已经设法使用以下代码检索了特定 company_id 的总和

db.analytics.aggregate([{
    $lookup: {
        from: "trees",
        as: "trees",
        localField: "tree_id",
        foreignField: "_id"
    }
}, {
    $lookup: {
        from: "links",
        as: "links",
        localField: "link_id",
        foreignField: "_id"
    }
}, {
    $match: {
        $or: [
            {"trees.company_id": "1"},
            {"links.company_id": "1"}
        ]
    }
}, {
    $group: {
        _id: null,
        views_count: {
            $sum: "$views"
        },
        clicks_count: {
            $sum: "$clicks"
        }
    }
}])

但我找不到获得类似结果列表的方法

{ company_id: 1, company_name: "foo", clicks: 100, views: 200 },
{ company_id: 2, company_name: "bar", clicks: 200, views: 200 }

等等。

到目前为止,我尝试的是按不同的 _id 分组,这并没有像我预期的那样工作

db.analytics.aggregate([{
    $lookup: {
        from: "trees",
        as: "trees",
        localField: "tree_id",
        foreignField: "_id"
    }
}, {
    $lookup: {
        from: "links",
        as: "links",
        localField: "link_id",
        foreignField: "_id"
    }
}, {
    $group: {
        _id: "$trees.company_id",
        views_count: {
            $sum: "$views"
        },
        clicks_count: {
            $sum: "$clicks"
        }
    }
}])

它不会将clicks_count 分配给特定条目,而是输出类似

{ "_id" : [ "1" ], "views_count" : 6, "clicks_count" : 0 }
{ "_id" : [ ], "views_count" : 0, "clicks_count" : 48 }
{ "_id" : [ "2" ], "views_count" : 10, "clicks_count" : 0 }

我什至不确定这个架构是否是最好的解决方案,所以我也会感谢任何设计建议或类似的东西。

根据下面的评论,我尝试在分组结果之前解构trees,但它只输出了company_id, views_count,没有计算clicks,如下

{ "_id" : "2", "views_count" : 10, "clicks_count" : 0 }
{ "_id" : "1", "views_count" : 6, "clicks_count" : 0 }

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:
    • $addFields添加公司字段,检查条件如果trees.company_id不为空[]则返回trees否则返回links
    • $arrayElemAt 从数组中获取第一个元素
    • $group company_id 并总结您的计数
    db.analytics.aggregate([
      { $lookup: { //... } },
      { $lookup: { //... } },
      {
        $addFields: {
          company: {
            $arrayElemAt: [
              { $cond: [{ $ne: ["$trees.company_id", []] }, "$trees", "$links"] },
              0
            ]
          }
        }
      },
      {
        $group: {
          _id: "$company.company_id",
          company_name: { $first: "$company.company_name" },
          views_count: { $sum: "$views" },
          clicks_count: { $sum: "$clicks" }
        }
      }
    ])
    

    Playground

    【讨论】:

    • 所以基本上你是从treeslinks 中添加company_id 到根文档,允许你按company.company_id 对所有文档进行分组?我不知道 mongodb 有多脏。但是,你拯救了我的一天! :)
    • 其实mongodb是直接不需要多个集合的,你的schema看起来像mysql,mongodb是nosql。
    • 所以您确实建议在根级别使用具有分析功能的单个集合(对于tree),并让links 与他们自己的analytics 嵌套?有道理,但我不确定它会如何影响性能
    • 确定我不了解您的项目概念,但很快我终于添加了一个新集合,新查询见playground,所以我刚刚添加了常见字段 company_id 和 company_name 和每个分析文档中的 url。所以我们删除了 2 个额外的集合,基本上在 nosql 中,每个文档中重复的数据/值并不重要,但可以防止多个集合和关系集合。您可以根据您的项目概念进一步改进此架构。
    猜你喜欢
    • 2017-10-08
    • 1970-01-01
    • 2021-11-16
    • 2018-08-19
    • 2020-10-05
    • 2019-01-21
    • 2019-09-03
    • 2020-09-07
    • 1970-01-01
    相关资源
    最近更新 更多