You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB查询:获取时序数据中每日首个true及后续false的子文档

搞定每日首个True状态时序文档的查询需求

嘿,我来帮你解决这个问题!首先得对齐下数据结构,我先基于你描述的信息假设一个典型的时序文档结构(如果和实际不符,你直接调整字段名就行):

{
  "_id": ObjectId("..."),
  "data": [2024, 5, 20, "09:00-09:15"], // 依次是年份、月份、日期、15分钟时间区间
  "status": true // 你提到的那个true/false状态字段
}

核心思路是用聚合管道按日期分组,把当天的文档按时间排序后,筛选出首个status: true的文档,再顺手抓它之后第一个status: false的文档。下面是具体的实现步骤:

第一步:预处理文档,做好分组和排序的准备

首先得把data里的日期信息提取出来作为分组键,同时把15分钟区间转成可排序的数值(方便按时间先后排序):

db.yourCollectionName.aggregate([
  // 新增日期标识和时间排序字段
  {
    $addFields: {
      // 把年/月/日转成YYYY-MM-DD格式的字符串,用来按天分组
      "dateKey": {
        $dateToString: {
          format: "%Y-%m-%d",
          date: {
            $dateFromParts: {
              year: { $arrayElemAt: ["$data", 0] },
              month: { $arrayElemAt: ["$data", 1] },
              day: { $arrayElemAt: ["$data", 2] }
            }
          }
        }
      },
      // 把15分钟区间转成当日的总分钟数(比如"09:00-09:15"转成540),方便排序
      "timeSort": {
        $let: {
          vars: {
            startTime: { $split: [{ $arrayElemAt: ["$data", 3] }, "-"] }
          },
          in: {
            $sum: [
              { $multiply: [{ $toInt: { $split: ["$$startTime", ":"] } }, 60] },
              { $toInt: { $arrayElemAt: [{ $split: ["$$startTime", ":"] }, 1] } }
            ]
          }
        }
      }
    }
  },
  // 按日期分组,把当天所有文档存进一个数组
  {
    $group: {
      _id: "$dateKey",
      dailyDocs: {
        $push: {
          data: "$data",
          status: "$status",
          timeSort: "$timeSort"
        }
      }
    }
  },
  // 把每组内的文档按时间先后排序
  {
    $addFields: {
      sortedDailyDocs: { $sortArray: { input: "$dailyDocs", sortBy: { timeSort: 1 } } }
    }
  }
])

第二步:筛选目标文档

接下来就在排序好的每日文档数组里,精准定位我们要的内容:

// 接上面的聚合管道,继续添加这些阶段
{
  $addFields: {
    // 找到第一个status为true的文档的索引
    firstTrueIndex: {
      $indexOfArray: ["$sortedDailyDocs.status", true]
    },
    // 提取第一个true的文档
    firstTrueDoc: {
      $cond: {
        if: { $ne: ["$firstTrueIndex", -1] }, // 检查当天有没有true的文档
        then: { $arrayElemAt: ["$sortedDailyDocs", "$firstTrueIndex"] },
        else: null
      }
    }
  }
},
{
  $addFields: {
    // 如果找到了第一个true文档,找它之后第一个false的文档
    followingFalseDoc: {
      $cond: {
        if: { $ne: ["$firstTrueIndex", -1] },
        then: {
          $let: {
            vars: {
              // 截取第一个true之后的所有文档
              docsAfterFirstTrue: { $slice: ["$sortedDailyDocs", { $add: ["$firstTrueIndex", 1] }, { $size: "$sortedDailyDocs" }] }
            },
            in: {
              $arrayElemAt: ["$$docsAfterFirstTrue", { $indexOfArray: ["$$docsAfterFirstTrue.status", false] }]
            }
          }
        },
        else: null
      }
    }
  }
},
// 整理输出格式,只保留我们需要的字段
{
  $project: {
    _id: 0,
    date: "$_id",
    firstTrueDocument: "$firstTrueDoc.data",
    followingFalseDocument: { $ifNull: ["$followingFalseDoc.data", null] }
  }
}

一些注意事项

  • 如果你的状态字段不是status,或者data数组的结构有差异(比如区间是数字而不是字符串),直接替换对应的字段名或调整时间转换逻辑就行。
  • 如果某一天没有status: true的文档,firstTrueDocument和followingFalseDocument都会返回null。
  • 要是你的数据库不是MongoDB,你可以告诉我具体的数据库类型,我再帮你调整查询语句~

内容的提问来源于stack exchange,提问作者Aaron Gayle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:13:36