You need to enable JavaScript to run this app. Node.js 中 Mongoose 如何查询嵌套数组的指定日期范围数据
优惠活动
大模型
产品
解决方案
定价
更多

Node.js 中 Mongoose 如何查询嵌套数组的指定日期范围数据

Mongoose嵌套数组日期查询的过滤问题与实现方案

Schema定义

用户存储的用户模型结构如下:

const User = mongoose.model(
  "User",
  new mongoose.Schema({
    email: String,
    password: String,
    name: String,
    days: [
      {
        day: Date,
        data:  
        { 
          average_score: {type: mongoose.Schema.Types.Decimal128, default: 0 }
        }
      }
    ]
  })
);

其中days数组内的day字段统一以ISO格式存储,例如2020-12-29T00:00:00.000Z。

问题表现

最初编写的查询逻辑希望筛选指定用户、且日期在指定范围内的数组元素:

User.find({ 
  "_id": getUserId(req), 
  "days.day":{
    "$gte": new Date("2021-01-02T00:00:00.000Z"), 
    "$lt": new Date("2021-01-04T00:00:00.000Z")
  }},
  function (err, result) {
    if (err){
      res.status(400).send({data: { message: err }});
      return;
    }
    res.status(200).send({data: { message: result }});
  }
)

实际运行结果:查询返回了匹配用户的全部days数组数据,没有只保留符合日期条件的片段。

问题本质:普通Mongoosefind查询的数组字段条件,仅判断文档内是否存在满足匹配规则的数组元素,不会对数组本身做裁剪,因此会返回完整的数组内容。

可落地的实现方案

使用聚合管道完成查询,通过$match匹配对应用户,再通过$project搭配$filter运算符逐元素过滤days数组,可精准返回符合条件的数组片段,实现代码如下:

let itsArray = Array.isArray(req.body.day)
let first = itsArray ?  new Date(new Date(req.body.day[0]).toISOString()) : null
let second = itsArray ? new Date(new Date(req.body.day[1]).toISOString()) : null
let theDay = itsArray ? null : new Date(req.body.day)
let now = new Date()
theDay = itsArray ? null :  new Date(new Date(theDay).toISOString())

// 单日查询过滤规则:匹配完全相等的日期
const objectProject = { $project: {
    days: {
      $filter: {
        input: "$days",
        as: "index", 
        cond:{ $eq: [ "$$index.day", theDay ] },
      }
    }
}}

// 范围查询过滤规则:匹配两个日期之间的闭区间元素
const arrayProject = { $project: {
    days: {
      $filter: {
        input: "$days",
        as: "index", 
        cond: {$and: [
          { $gte: [ "$$index.day", first ] },
          { $lte: [ "$$index.day", second ] }
        ]}
      }
    }
}}

await User.aggregate([
  {$match:{_id: ObjectID(getUserId(req))}},
  itsArray ? arrayProject : objectProject
])
.project({'days.day':1, 'days.data':1})
.then(result => {console.log(result)})

该方案通过$match、$project、$filter的聚合组合,可得到符合预期的查询结果。


内容的提问来源于stack exchange,提问作者Mr. Stefan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 21:36:10