MongoDB基于日期中多个因素的汇总/索引

时间:2018-09-04 03:10:53

标签: mongodb aggregation-framework mongodb-indexes

我正在寻找索引/汇总大量电视节目的最有效方法,以便获得在特定日期播出的每个节目的平均收视率。

理想情况下,用户应以ISO格式(YYYY-MM-DD)提供日期,汇总汇总返回当天播出的节目列表,以及包含其30天平均值的字段。

目前,我有2个收藏集,DatesShows。这是一个简化的示例:

// Dates (provides parent_id to link show records by date)
{ _id: 1, dataDate: 2018-09-01T00:00:00-04:00 }
{ _id: 2, dataDate: 2018-09-02T00:00:00-04:00 }

// Shows 
{  
  parent_id: 1,
  name: "SHOW A",
  start: 2018-09-01T19:00:00-04:00,
  end: 2018-09-01T20:00:00-04:00,
  rating: 100
},{ 
  parent_id: 1,
  name: "SHOW B",
  start: 2018-09-01T20:00:00-04:00,
  end: 2018-09-01T21:00:00-04:00,
  rating: 150
},{ 
  parent_id: 1,
  name: "SHOW C",
  start: 2018-09-01T21:00:00-04:00,
  end: 2018-09-01T22:00:00-04:00,
  rating: 200
}, {  
  parent_id: 2,
  name: "SHOW A",
  start: 2018-09-02T19:00:00-04:00,
  end: 2018-09-02T20:00:00-04:00,
  rating: 100
},{ 
  parent_id: 2,
  name: "SHOW B",
  start: 2018-09-02T20:00:00-04:00,
  end: 2018-09-02T21:00:00-04:00,
  rating: 150
},{ 
  parent_id: 2,
  name: "SHOW C",
  start: 2018-09-02T21:00:00-04:00,
  end: 2018-09-02T22:00:00-04:00,
  rating: 200
}

这是我目前的做法-

  • 用户在Dates集合中请求的查找日期
  • 使用日期记录中的ID匹配parent_id的节目
  • 对于每个节目,查找过去30集(根据名称,开始/结束时间)
  • 使用$ avg将$ lookup的结果分组
  • 将平均字段合并到原始表演记录中

现在,这需要花费大量时间才能完成。我在集合上有2个索引,{ parent_id: 1 }{ start: -1, name: 1 }。如果删除第二个match语句的最后3个阶段(检查节目名称和开始/结束时间),它将立即返回。但是,我需要检查这些变量,以免将重播(同一名称的节目在一天中的不同时间播出)显示在最终结果中。有更好的方法对此进行索引吗?还是这里有特定的陈述在拖慢速度?

let dataDate = DateTime.fromISO('2018-09-01').setZone('America/New_York');
let avgDate = DateTime.fromISO('2018-09-01').setZone('America/New_York').minus({ days: 30 });

let parent = Dates.findOne({ dataDate: dataDate.toJSDate() });

db.shows.aggregate([{
        $match: {
            parent_id: parent._id
        }
    }, {
        $lookup: {
            from: 'shows',
            let: { 
                name: '$name', 
                start: { $hour: { date: '$start', timezone: 'America/New_York' } }, 
                end: { $hour: { date: '$end', timezone: 'America/New_York' } } },
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $lt: [ '$start', dataDate.toJSDate() ] },
                            { $gte: [ '$start', avgDate.toJSDate() ] },
                            { $eq: [ '$name', '$$name' ] },
                            { $eq: [ { $hour: { date: '$start', timezone: 'America/New_York' } }, '$$start' ] },
                            { $eq: [ { $hour: { date: '$end', timezone: 'America/New_York' } }, '$$end' ] },
                        ]
                    }
                }
            }, {
                $group: {
                    _id: null,
                    averageRating: { $avg: `$$rating` }
                }
            }],
            as: 'average'
        }
    }, {
        $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ['$average', 0] }, "$$ROOT"] } }
    }, {
        $project: {
            channel_id: 1,
            start: 1,
            end: 1,
            todayRating: `$$rating`,
            averageRating: 1,
            name: 1,
        }
    }])

0 个答案:

没有答案