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

Mongoose如何实现日期时间区间的多条件组合查询

Mongoose 操作 MongoDB 多条件+时间范围查询实现

现有集合结构

项目中报告集合的示例数据如下:

[
 {
    _id: new ObjectId("62ae97b6be08b688f93f2c07"),
    reportId: '1',
    method: 'A1',
    category: 'B2',
    date: '2022-06-19',
    time: '22:55',
    emergency: 'normal',
    __v: 0
  },
  {
    _id: new ObjectId("62ae97b6be08b688f93f2c08"),
    reportId: '2',
    method: 'A3',
    category: 'B5',
    date: '2022-06-18',
    time: '23:05',
    emergency: 'normal',
    __v: 0
  },
  {
    _id: new ObjectId("62ae97b6be08b688f93f2c09"),
    reportId: '3',
    method: 'A5',
    category: 'B1',
    date: '2022-06-19',
    time: '23:55',
    emergency: 'urgent',
    __v: 0
  }
]

已实现基础逻辑

当前已经完成method、emergency、category三个字段的枚举值匹配筛选,代码如下:

const options = [
 { method: { $in: ['A1','A2'] } },
 { emergency: { $in: data.emergency } },
 { category: { $in: data.category } }
];

const response = await Report.find({ $or: options,});

待实现需求

新增时间范围筛选规则:集合内date、time字段均为字符串类型,需要筛选出时间落在前一日23点之后、当日23点之前的所有数据。
之前尝试使用$where结合moment.js编写测试逻辑,不确定正确性,测试代码如下:

date: {
       $where: function () {
              const yesterday = moment().subtract(1, 'days').format('YYYYMMDD') + '2300';
              const date = moment(this.date).format('YYYYMMDD') + this.time.replace(':', '');
              const today = moment().format('YYYYMMDD') + '2300';
              return yesterday < date && date <= today;
            },
          },

问题说明与正确实现

原有$where写法的问题

  • 语法错误:$where是顶级查询操作符,不能嵌套在date字段的查询对象内
  • 执行错误:$where的逻辑在MongoDB服务端运行,默认环境没有moment依赖,直接调用会抛出异常
  • 性能缺陷:$where会触发全表扫描,无法命中索引,数据量较大时查询延迟极高,生产环境不推荐使用

推荐方案(原生操作符实现,性能最优)

由于存储的date字段为YYYY-MM-DD格式、time字段为HH:mm格式,字符串的字典排序规则和实际时间顺序完全一致,不需要做日期类型转换,直接通过字符串比较即可实现范围筛选,还可以支持联合索引优化查询速度。
时间范围可以拆分为两个并列区间匹配:

  1. 日期为前一天,且时间大于23:00
  2. 日期为当天,且时间小于23:00

完整查询代码如下,注意两个$or条件需要用$and包裹,避免同名字段覆盖:

const moment = require('moment');
// 提前在Node侧计算边界日期,自动处理跨月、跨年场景
const yesterday = moment().subtract(1, 'days').format('YYYY-MM-DD');
const today = moment().format('YYYY-MM-DD');

const baseFilterOptions = [
 { method: { $in: ['A1','A2'] } },
 { emergency: { $in: data.emergency } },
 { category: { $in: data.category } }
];

const response = await Report.find({
  $and: [
    // 原有基础筛选条件
    { $or: baseFilterOptions },
    // 新增时间范围筛选
    {
      $or: [
        {
          date: yesterday,
          time: { $gt: '23:00' }
        },
        {
          date: today,
          time: { $lt: '23:00' }
        }
      ]
    }
  ]
});

不推荐的$where修正写法(仅作参考)

如果特殊场景必须使用$where,需要提前在Node侧计算好时间阈值,以字符串拼接的方式传入查询语句,不要在服务端执行逻辑里依赖外部库:

const moment = require('moment');
const yesterdayThreshold = moment().subtract(1, 'days').format('YYYYMMDD') + '2300';
const todayThreshold = moment().format('YYYYMMDD') + '2300';

const response = await Report.find({
  $and: [
    { $or: baseFilterOptions },
    {
      $where: `function() {
        const recordTime = this.date.replace(/-/g, '') + this.time.replace(':', '');
        return recordTime > '${yesterdayThreshold}' && recordTime < '${todayThreshold}';
      }`
    }
  ]
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:45:37