【问题标题】:Mongoose Aggregation does not Filter by Input DateMongoose 聚合不按输入日期过滤
【发布时间】:2016-06-09 21:22:15
【问题描述】:

我正在尝试构建一个聚合查询,但是当我将 $match 与日期一起使用时,它并没有像我预期的那样工作。如果我使用其他字段而不是任何 Date 字段,它会按预期工作。我正在使用的代码示例如下:

const res = await Reservation.aggregate([{ $match: { createdAt: { $lte: req.endDate } } }]).exec();

const res = await Reservation.find({ createdAt: { $lte: req.endDate } }).exec();

第一行不起作用,但第二行完美。 .find().aggregate() 有什么区别。感谢您的帮助!

【问题讨论】:

  • 您是否也尝试过流畅的管道构建器 API Reservation.aggregate().match({ createdAt: { $lte: req.endDate } }).exec()
  • @chridam,是的。它没有工作

标签: mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

Mongoose 有“模式”,它会为您执行称为“自动投射”的神奇事情。设计师在这里想到的典型情况是,来自“网络”交互(如GETPOST)的所有输入基本上都包含在“字符串”中。

无论是否有一些帮助器将参数转换为具有键和值的对象,所有这些“值”仍然是“字符串”,或者可能在适当的情况下由相同的“帮助器”直接数字化。这是常见的 Web 框架设计。

因此,当您发出.find() 时,除了省略字段/属性之外,此函数完全无法更改返回的内容,因此应用了“模式”。

.aggregate() 方法完全不同。它的全部存在就是修改文档和集合中包含的内容。这样做的结果是“不可能”应用模式。

因此,.find() 等方法中存在的“自动转换”不会发生,您需要转换元素(例如“日期”发送的“字符串”为) 到正确的类型:

Reservation.aggregate([
   { "$match": { "createdAt": { "$lte": new Date(req.endDate) } } }
])

即使您所做的只是$match 并且您没有以任何方式“修改”架构,mongoose 也不会“假定”这一点并且不会尝试转换到架构中的匹配字段。

这里的逻辑是$match 阶段或任何可以绑定到“类型”的类似内容,可能出现在管道中的任何位置。因此,无法保证管道阶段所处理的文档与原始集合模式有任何相似之处。

可以说它“可以”考虑到这样一个事实,即这第一个可能没有任何变化的管道阶段并进行类似的检查。但这不是当前代码库的工作方式。

因此,简而言之,当使用聚合管道时,所有需要专门转换为类型(Date、ObjectId 等)的对象都需要在代码中“手动”转换,而不是假设 mongoose 会这样做像其他方法一样为您服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-07
    • 2021-10-16
    • 2020-12-24
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    相关资源
    最近更新 更多