如何基于MongoDB中query字段频次获取指定时段的文档排名?
MongoDB按指定时间范围统计Query频次并生成排名
可以通过MongoDB的聚合管道实现这个需求,以下是具体的实现方案:
核心聚合逻辑
通过聚合管道的多阶段组合,完成过滤、统计、排序、排名的完整流程:
- 过滤时间范围:用
$match筛选出指定时间区间内的文档 - 分组统计频次:用
$group按目标字段(这里是query)分组,计算每个值的出现次数 - 按频次排序:用
$sort根据统计出的频次降序排列结果 - 生成排名:用
$setWindowFields为每个分组添加连续的排名字段 - 整理输出格式:用
$project调整输出字段结构,匹配预期的返回格式
完整聚合代码示例
假设你的集合名为queries,对应的聚合查询如下:
const startUnix = 1660610670; const endUnix = 1660610682; db.queries.aggregate([ // 1. 匹配指定时间范围的文档 { $match: { createdAt: { $gte: startUnix, $lt: endUnix } } }, // 2. 分组统计每个query的频次 { $group: { _id: "$query", frequency: { $sum: 1 } } }, // 3. 按频次降序排序 { $sort: { frequency: -1 } }, // 4. 计算排名(按频次降序,相同频次会获得相同排名) { $setWindowFields: { sortBy: { frequency: -1 }, output: { rank: { $rank: {} } } } }, // 5. 调整输出字段,把_id改为query { $project: { _id: 0, rank: 1, query: "$_id", frequency: 1 } } ])
封装成指定调用方式(以Mongoose为例)
如果使用Mongoose操作,可以给Queries模型添加静态方法getRank,适配你预期的调用格式:
Queries.schema.statics.getRank = async function(params) { const { key, createdAt } = params; return this.aggregate([ { $match: { createdAt } }, { $group: { _id: `$${key}`, frequency: { $sum: 1 } } }, { $sort: { frequency: -1 } }, { $setWindowFields: { sortBy: { frequency: -1 }, output: { rank: { $rank: {} } } } }, { $project: { _id: 0, rank: 1, [key]: "$_id", frequency: 1 } } ]); }; // 调用示例 const result = await Queries.getRank({ key: 'query', createdAt: { $gte: startUnix, $lt: endUnix } });
注意事项
- 如果需要处理并列排名(比如两个query频次相同),可以用
$denseRank替代$rank,$denseRank不会跳过并列后的排名数字 - 建议给
createdAt字段创建索引,避免数据量较大时时间范围匹配的性能问题
内容的提问来源于stack exchange,提问作者ton1
相关产品推荐
相关产品推荐

