如何对MongoDB聚合查询的返回结果进行二次筛选获取指定数据
方案1:聚合端直接预分组(最优,性能最高)
你可以直接在MongoDB的聚合pipeline里完成15分钟间隔的分组计算,不需要把全量数据拉到客户端再筛选,性能远高于客户端处理逻辑,同时还能优化原有重复计算$dateFromString的冗余逻辑:
qryData = collection.aggregate([ # 仅做一次时间格式转换,避免重复计算 { "$addFields": { "ts_date": { "$dateFromString": { "dateString": "$timestamp", "format": "%Y-%m-%d %H:%M:%S" } } } }, # 筛选指定日期和城市的所有数据 { "$match": { "$expr": { "$and": [ { "$eq": [{ "$year": "$ts_date" }, dateToChart.year] }, { "$eq": [{ "$month": "$ts_date" }, dateToChart.month] }, { "$eq": [{ "$dayOfMonth": "$ts_date" }, dateToChart.day] } ] }, "name": city } }, # 直接按15分钟粒度分组 { "$group": { "_id": { "hour": { "$hour": "$ts_date" }, # 分钟对齐到15分钟槽:0/15/30/45 "minute_slot": { "$multiply": [{ "$floor": { "$divide": [{ "$minute": "$ts_date" }, 15] }}, 15] } }, # 可按需调整聚合逻辑:存所有原始数据、计算平均值/求和等 "data_points": { "$push": "$$ROOT" } } } ])
返回结果已经按15分钟时间槽分好组,遍历你的15分钟时间数组时,直接匹配hour和minute_slot就能快速拿到对应数据,不需要额外筛选。
方案2:客户端侧快速索引(如果需要保留全量原始数据)
如果你确实需要拉取全量指定日期数据到客户端处理,不要使用双层循环,MongoDB的CommandCursor仅支持单次遍历,且双层循环时间复杂度为O(n*m),数据量较大时性能极差。可以通过构建索引把复杂度降到O(n+m):
# 先把游标转成列表,避免无法重复遍历的问题 all_data = list(qryData) # 构建时间槽索引 data_index = {} for item in all_data: minute_slot = (item['minute'] // 15) * 15 key = (item['hour'], minute_slot) if key not in data_index: data_index[key] = [] data_index[key].append(item) # 遍历时间数组时直接匹配索引 filtered_data = [] for time in times: key = (time.hour, (time.minute //15)*15) filtered_data.extend(data_index.get(key, []))
小提示:你之前写的双层循环示例存在两处语法问题:一是相等判断应该用
==,二是取值应该用results["hour"]而非qryData["hour"],直接运行会报错。
内容的提问来源于stack exchange,提问作者Tyler N
相关产品推荐
相关产品推荐

