Mongoose 聚合不按输入日期过滤

Posted

技术标签:

【中文标题】Mongoose 聚合不按输入日期过滤【英文标题】:Mongoose Aggregation does not Filter by Input Date 【发布时间】: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,是的。它没有工作 【参考方案1】:

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

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

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

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

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

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

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

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

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

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

【讨论】:

以上是关于Mongoose 聚合不按输入日期过滤的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose: aggregate聚合 $group使用说明

Mongoose 聚合查找 - 如何按特定 id 过滤

Mongoose:聚合获取数组类型字段的文档并根据特定字段过滤这些文档

Mongoose 聚合:基于 Model.associated_Model.associated_Model.field 过滤返回错误结果

修改对象中的日期以在 mongoose 中进行聚合 $match 查询

具有 .every() 等效项的 Mongoose 聚合