我在MongoDB中有一个文档集合,表示某个实体。每个实体每天都收集一些统计数据。统计数据作为单独的文档放入不同的集合中。
实体集合模式:
{
_id: ObjectId,
filterField1: String, //indexed
filterField2: String, //indexed
}统计数据收集的示例模式:
{
_id: ObjectId,
entityId: ObjectId, //indexed
statisticsValue: Int32,
date: Date //indexed
}有一个仪表板需要根据收集到的数据显示一些聚集的统计信息。平均值、和、计数等。仪表板允许过滤实体和应用不同的日期范围,这使得预先计算这些汇总统计数据成为不可能的。
目前,我一直在使用聚合管道来:
aggregation
的统计信息。
这是管道:
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
但是我不确定MongoDB是否适合这样的操作,如果我想执行这样的查询,也许我应该考虑另一个数据源。
发布于 2022-06-23 14:13:16
很难猜,你想得到什么。一种方法可以是这样的:
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" }
}
}
]);https://stackoverflow.com/questions/72712532
复制相似问题