我正在寻找索引/汇总大量电视节目的最有效方法,以便获得在特定日期播出的每个节目的平均收视率。
理想情况下,用户应以ISO格式(YYYY-MM-DD)提供日期,汇总汇总返回当天播出的节目列表,以及包含其30天平均值的字段。
目前,我有2个收藏集,Dates
和Shows
。这是一个简化的示例:
// 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
集合中请求的查找日期parent_id
的节目现在,这需要花费大量时间才能完成。我在集合上有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,
}
}])