【发布时间】:2016-07-10 16:03:43
【问题描述】:
如果我的 mongoDB 中保存了以下架构中的文档:
{
createdDate: Date,
lastUpdate: Date
}
是否可以查询从创建到最后一次更新之间的时间段的文档,例如超过一天?
【问题讨论】:
标签: mongodb mongodb-query aggregation-framework
如果我的 mongoDB 中保存了以下架构中的文档:
{
createdDate: Date,
lastUpdate: Date
}
是否可以查询从创建到最后一次更新之间的时间段的文档,例如超过一天?
【问题讨论】:
标签: mongodb mongodb-query aggregation-framework
最好的选择是使用$redact 聚合管道阶段:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$gt": [
{ "$subtract": [ "$lastUpdate", "$createdDate" ] },
1000 * 60 * 60 * 24
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
因此,您正在查看毫秒值的差异大于一天的毫秒值。 $subtract 计算差异,当减去两个日期时,返回以毫秒为单位的差异。
$redact 运算符将逻辑表达式作为“if”,在该条件为true 的情况下,它在“then”中执行操作,即对文档$$KEEP。如果是false,那么文档会从带有$$PRUNE 的结果中删除。
请注意,由于这是一个逻辑条件,而不是设定值或值范围,因此不使用“索引”。
由于聚合管道中的操作是本机编码的,因此这是您可以获得的最快执行此类语句的方法。
替代方法是使用 $where 进行 JavaScript 评估。这需要一个 JavaScript 函数表达式,该表达式需要类似地返回 true 或 false 值。在 shell 中,你可以这样简写:
db.collection.find(function() {
return ( this.lastUpdate.valueOf() - this.createdDate.valueOf() )
> ( 1000 * 60 * 60 * 24 );
})
同样的事情,除了 JavaScript 评估需要解释并且运行速度比 .aggregate() 等效的要慢得多。同理,这种类型的表达式不能使用索引来优化性能。
为了获得最佳结果,请将差异存储在文档中。然后你可以直接查询那个属性,当然你也可以索引它。
【讨论】:
您可以使用$expr(3.6 mongo 版本运算符)在常规查询中使用聚合函数。
比较 query operators 与 aggregation comparison operators。
db.col.find({$expr:{$gt:[{"$subtract":["$lastUpdate","$createdDate"]},1000*60*60*24]}})
【讨论】:
从Mongo 5 开始,这是新的$dateDiff 聚合运算符的完美用例:
// { created: ISODate("2021-12-05T13:20"), lastUpdate: ISODate("2021-12-06T05:00") }
// { created: ISODate("2021-12-04T09:20"), lastUpdate: ISODate("2021-12-05T18:00") }
db.collection.aggregate([
{ $match: {
$expr: {
$gt: [
{ $dateDiff: { startDate: "$created", endDate: "$lastUpdate", unit: "hour" } },
24
]
}
}}
])
// { created: ISODate("2021-12-04T09:20"), lastUpdate: ISODate("2021-12-05T18:00") }
这会计算 created 和 lastUpdate 日期之间的小时数差异,并检查它是否大于 24 hours。
【讨论】: