首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB优化大型聚合查询

MongoDB优化大型聚合查询
EN

Stack Overflow用户
提问于 2022-06-22 09:00:50
回答 1查看 124关注 0票数 0

我在MongoDB中有一个文档集合,表示某个实体。每个实体每天都收集一些统计数据。统计数据作为单独的文档放入不同的集合中。

实体集合模式:

代码语言:javascript
复制
{
  _id: ObjectId,
  filterField1: String, //indexed
  filterField2: String, //indexed
}

统计数据收集的示例模式:

代码语言:javascript
复制
{
  _id: ObjectId,
  entityId: ObjectId, //indexed
  statisticsValue: Int32,
  date: Date //indexed
}

有一个仪表板需要根据收集到的数据显示一些聚集的统计信息。平均值、和、计数等。仪表板允许过滤实体和应用不同的日期范围,这使得预先计算这些汇总统计数据成为不可能的。

目前,我一直在使用聚合管道来:

aggregation

  • make

  • 将筛选器应用于实体集合(使用匹配阶段)

  • 进行必要的查找阶段,以获取

  • 分组和聚合(avg、sum、count等)

的统计信息。

这是管道:

代码语言:javascript
复制
db.getCollection('entities').aggregate([
    { $match: { $expr: { $and: [ 
        // ENTITIES FILTERS based on filterField1 and filterField2 fields 
    ] } } },
    { $lookup: {
        from: 'statistics',
        let: { entityId: '$_id' },
        pipeline: [{ $match: { $expr: { $and: [
            { $eq: ["$entityId", "$$entityId"] },
            { $gte: [ "$date", new ISODate("2022-06-01T00:00:00Z") ] },
            { $lte: [ "$date", new ISODate("2022-06-01T23:59:59Z") ] },
        ] } } },
        as: 'stats_start_date_range',
     } },
     { $lookup: {
        from: 'statistics',
        let: { key: '$_key' },
        pipeline: [{ $match: { $expr: { $and: [
            { $eq: ["$entityId", "$$entityId"] },
            { $gte: [ "$date", new ISODate("2022-06-31T00:00:00Z") ] },
            { $lte: [ "$date", new ISODate("2022-06-31T23:59:59Z") ] },
        ] } } },
        as: 'stats_end_date_range',
     } },
     { $addFields: 
       { 
         start_stats: { $first: "$stats_start_date_range" }, 
         end_stats: { $first: "$stats_end_date_range" } 
       }
     },
     {
       $group: {
         _id: null,
         avg_start: { $avg:  "$start_stats.statisticsValue" },
         avg_end: { $avg:  "$end_stats.statisticsValue" }
       }   
    }
])

对于此查询,预期结果是匹配筛选器的每个实体的开始日期和结束日期的statisticsValue字段的平均值。

我将索引应用于用于在查找阶段离开联接集合的字段。以及用于获取特定日期的统计信息的日期字段。

问题是,在匹配阶段之后(大约1000个文档),查询所需的最大文档数大约为1秒。我需要执行4个这样的查询。统计数据集包含80万份文档,而且数量每天都在增加。

我在想,如果我能做些什么来加快查询的执行速度,我会考虑:

使用facet stage collection

  • reorganizing 将这4个独立查询合并为1的
  • 时间序列
  • 集合结构(不知道如何实现)

但是我不确定MongoDB是否适合这样的操作,如果我想执行这样的查询,也许我应该考虑另一个数据源。

EN

回答 1

Stack Overflow用户

发布于 2022-06-23 14:13:16

很难猜,你想得到什么。一种方法可以是这样的:

代码语言:javascript
复制
const entities = db.getCollection('entities').aggregate([
   { $match: { filterField1: "a" } }
]).toArray().map(x => x._id)

db.getCollection('statistics').aggregate([
   {
      $match: {
         entityId: { $in: entities },
         date: {
            $gte: ISODate("2022-06-01T00:00:00Z"),
            $lte: ISODate("2022-06-31T23:59:59Z")
         }
      }
   },
   {
      $facet: {
         stats_start_date_range: [
            {
               $match: {
                  date: {
                     $gte: ISODate("2022-06-01T00:00:00Z"),
                     $lte: ISODate("2022-06-01T23:59:59Z")
                  }
               }
            }
         ],
         stats_end_date_range: [
            {
               $match: {
                  date: {
                     $gte: ISODate("2022-06-31T00:00:00Z"),
                     $lte: ISODate("2022-06-31T23:59:59Z")
                  }
               }
            }
         ]
      }
   },
   {
      $addFields: {
         start_stats: { $first: "$stats_start_date_range" },
         end_stats: { $first: "$stats_end_date_range" }
      }
   },
   {
      $group: {
         _id: null,
         avg_start: { $avg: "$start_stats.statisticsValue" },
         avg_end: { $avg: "$end_stats.statisticsValue" }
      }
   }
]);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72712532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档