基于Date字段的时间序列数据查询:动态匹配hourly子字段
动态匹配并保留MongoDB文档中对应分钟的hourly子字段
要实现根据date字段的分钟值,只保留hourly中对应键的子字段这个需求,MongoDB的聚合框架完全可以搞定,下面是具体的实现方案和步骤:
核心思路
- 从
date字段中提取分钟数值,转换成字符串(因为hourly的键是字符串类型,比如"0"、"1"); - 将
hourly对象转换为键值对数组,过滤出键与分钟字符串匹配的元素; - 把过滤后的数组转回对象,替换原有的
hourly字段,同时保留文档的其他字段。
完整聚合管道
db.collection.aggregate([ // 提取date的分钟值并转为字符串 { $addFields: { minuteStr: { $toString: { $minute: "$date" } } } }, // 转换hourly为数组并过滤出匹配的键值对 { $addFields: { filteredHourly: { $filter: { input: { $objectToArray: "$hourly" }, cond: { $eq: ["$$this.k", "$minuteStr"] } } } } }, // 重构文档,保留需要的字段并生成新的hourly { $project: { _id: 1, date: 1, metadata: 1, hourly: { $arrayToObject: "$filteredHourly" } } }, // 可选:过滤掉hourly为空的文档(如果存在分钟值无对应hourly键的情况) { $match: { $expr: { $ne: ["$hourly", {}] } } } ])
各阶段说明
- $addFields(提取分钟):使用
$minute操作符从ISODate类型的date字段中获取分钟数值,再用$toString转换为字符串,确保和hourly的键类型一致,避免匹配失败。 - $addFields(过滤hourly):
$objectToArray把hourly对象拆分为[{k: "键名", v: 字段值}, ...]格式的数组,接着$filter遍历数组,只保留键等于minuteStr的元素。 - $project(重构文档):保留原文档的
_id、date和metadata字段,同时用$arrayToObject把过滤后的键值对数组重新转换为对象,作为新的hourly字段。 - 可选$match:如果你的数据中存在
date分钟值在hourly中没有对应键的情况,这个阶段可以过滤掉那些hourly为空对象的结果,避免无效数据。
验证示例
假设你的原始文档是:
{ "_id" : "08062017/cpu", "date" : ISODate("2018-04-11T02:01:00.000Z"), "metadata" : { "host" : "localhost", "metric" : "cpu" }, "hourly" : { "0" : { "total" : 234, "used" : 123 }, "1" : { "total" : 234, "used" : 123 } } }
因为date的分钟是1,minuteStr为"1",所以聚合后得到的结果会是:
{ "_id" : "08062017/cpu", "date" : ISODate("2018-04-11T02:01:00.000Z"), "metadata" : { "host" : "localhost", "metric" : "cpu" }, "hourly" : { "1" : { "total" : 234, "used" : 123 } } }
(注:你提供的期望结果中保留了hourly.0,应该是示例的笔误,实际按照分钟值1会匹配到hourly.1)
内容的提问来源于stack exchange,提问作者David Ramsaran
相关产品推荐
相关产品推荐

