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

MongoDB筛选lifeCycleInfo数组中completed早于created事件的文档

筛选MongoDB中payment.completed早于payment.created的文档

我正在用MongoDB Compass执行查询,需要从数千条文档里筛选特定记录。每条文档都包含lifeCycleInfo数组,部分文档中数组内的payment.completed事件发生在payment.created事件之前,我要找出这类记录。

之前尝试按数组索引查询没生效,用的语句是:

{"lifeCycleInfo[1].eventtype":"payment.completed"}

示例文档结构如下:

{
  "lifeCycleInfo": [
    {
      "eventId": "9b8b6adfae",
      "eventSubType": "SendTransfer_Receipt",
      "eventType": "SendTransfer",
      "odsTimestamp": {
        "$date": "2023-02-06T14:33:42.308Z"
      },
      "payload": "{}",
      "timestamp": {
        "$date": "2023-02-06T14:33:42.271Z"
      }
    },
    {
      "eventId": "06e8d144-531b02",
      "eventSubType": "payment.created",
      "eventType": "Notification",
      "odsTimestamp": {
        "$date": "2023-02-06T14:33:45.488Z"
      },
      "payload": "{}",
      "timestamp": {
        "$date": "2023-02-06T14:33:45.479Z"
      }
    },
    {
      "eventId": "9da54454d6",
      "eventSubType": "payment.completed",
      "eventType": "Notification",
      "odsTimestamp": {
        "$date": "2023-02-06T14:33:46.698Z"
      },
      "payload": "{}",
      "timestamp": {
        "$date": "2023-02-06T14:33:46.689Z"
      }
    }
  ]
}

问题分析

之前的查询失效有两个核心原因:

  • 字段名错误:MongoDB字段名区分大小写,应该用eventSubType而非eventtype
  • 固定索引不可靠:lifeCycleInfo数组内的事件顺序不固定,不能硬指定索引位置判断事件先后

解决方案

方式一:使用find结合$expr直接查询

适合在MongoDB Compass的查询栏直接使用:

db.collection.find({
  // 先过滤出同时包含两个目标事件的文档,避免无意义的比较
  "lifeCycleInfo.eventSubType": { $all: ["payment.completed", "payment.created"] },
  $expr: {
    $lt: [
      // 提取payment.completed的最早时间戳
      {
        $min: {
          $map: {
            input: { $filter: { input: "$lifeCycleInfo", cond: { $eq: ["$$this.eventSubType", "payment.completed"] } } },
            as: "completed",
            in: "$$completed.timestamp"
          }
        }
      },
      // 提取payment.created的最早时间戳
      {
        $min: {
          $map: {
            input: { $filter: { input: "$lifeCycleInfo", cond: { $eq: ["$$this.eventSubType", "payment.created"] } } },
            as: "created",
            in: "$$created.timestamp"
          }
        }
      }
    ]
  }
})

方式二:使用聚合管道分步处理

如果需要查看中间过程,或后续要做更多数据处理,用聚合管道更清晰:

db.collection.aggregate([
  // 第一步:过滤出同时包含两个事件的文档
  { $match: { "lifeCycleInfo.eventSubType": { $all: ["payment.completed", "payment.created"] } } },
  // 第二步:提取两个事件的时间戳到临时字段
  {
    $addFields: {
      completedTime: {
        $min: {
          $map: {
            input: { $filter: { input: "$lifeCycleInfo", cond: { $eq: ["$$this.eventSubType", "payment.completed"] } } },
            as: "item",
            in: "$$item.timestamp"
          }
        }
      },
      createdTime: {
        $min: {
          $map: {
            input: { $filter: { input: "$lifeCycleInfo", cond: { $eq: ["$$this.eventSubType", "payment.created"] } } },
            as: "item",
            in: "$$item.timestamp"
          }
        }
      }
    }
  },
  // 第三步:筛选出completed时间早于created的文档
  { $match: { $expr: { $lt: ["$completedTime", "$createdTime"] } } },
  // 可选:移除临时字段,恢复原文档结构
  { $project: { completedTime: 0, createdTime: 0 } }
])

说明

两种方式都通过$filter提取目标事件,用$min获取事件的最早时间戳(如果一个文档有多个同类型事件,取最早的那个比较),最后通过$lt判断时间先后。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:40:34