Mongo $subtract date 在聚合 $match 块中不起作用
Mongo $subtract date doesn't work in aggregation $match block
我正在创建一个 mongo 聚合查询,它在我的 $match 块中使用 $subtract 运算符。正如下面这些代码中所解释的。
此查询无效:
db.coll.aggregate(
[
{
$match: {
timestamp: {
$gte: {
$subtract: [new Date(), 24 * 60 * 60 * 1000]
}
}
}
},
{
$group: {
_id: {
timestamp: "$timestamp"
},
total: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
timestamp: "$_id.timestamp",
total: "$total",
}
},
{
$sort: {
timestamp: -1
}
}
]
)
但是,第二个查询有效:
db.coll.aggregate(
[
{
$match: {
timestamp: {
$gte: new Date(new Date() - 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: {
timestamp: "$timestamp"
},
total: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
timestamp: "$_id.timestamp",
total: "$total",
}
},
{
$sort: {
timestamp: -1
}
}
]
)
我需要在我的 $match
块上使用 $subtract
,所以我不能使用最后一个查询。
$subtract
运算符是投影运算符。它仅在 $project
步骤期间可用。所以你的选择是:
- (不推荐)在您的$match-step 之前添加一个$project-step 以转换所有文档的
timestamp
字段以用于后续的match-step。我不建议您这样做,因为此操作需要对数据库中的每个文档执行,并且会阻止数据库在时间戳字段上使用索引,因此可能会消耗大量性能。
- (推荐)在应用程序的 shell / 中生成要匹配的日期。生成一个新的 Date() 对象,将其存储在一个变量中,从中减去 24 小时并使用该变量执行第二次查询。
好吧,你不能那样做,你也不打算那样做。另一件有效的事情是你对 "need" 说要这样做,但实际上你真的没有这样做。
几乎所有一般 aggregation operators outside of the pipeline operators are really only valid within a $project
or a $group
流水线阶段。主要在 $project
内,但肯定不在其他人内。
一个$match
pipeline is really the same as a general "query" operation, so the only things valid in there are the query operators.
至于您的 "need" 的情况,在聚合管道内提交的任何 "value",特别是在 $match
内提交的任何 "value" 都需要在实际管道之外进行评估,然后再BSON表示被发送到服务器。
唯一的例外是文档中定义变量的符号,特别是 "fieldnames" 这样的 "$fieldname"
,然后才真正出现在 $project
或 $group
中。所以这意味着 "refers" 到文档的现有值,这是在任何类型的 "query" 文档表达式中无法完成的事情。
如果您需要使用文档中另一个字段的值,那么您首先使用 $project
进行计算,如:
db.collection.aggregate([
{ "$project": {
"fieldMath": { "$subtract": [ "$fieldOne", "$fieldTwo" ] }
}},
{ "$match": { "fieldMath": { "$gt": 2 } }}
])
出于任何其他目的,您确实想要评估管道的价值 "outside"。
以上回答了您提出的问题,但这回答了您没有提出的问题。
您的管道没有任何意义,因为单独对 "timestamp" 进行分组不太可能对任何内容进行分组,因为这些值的精度为毫秒,而且最多可能不会超过几个对于非常活跃的系统。
您似乎正在寻找要按 "day" 分组的数学运算,您可以这样做:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$timestamp", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$timestamp", new Date(0) ] },
1000 * 60 * 60 * 24
]}
]
},
"total": { "$sum": "$total" }
}}
])
那 "rounds" 你的时间戳值到一天,并且有更好的机会 "aggregating" 比你本来拥有的东西。
或者您可以使用 "date aggregation operators" 与复合键做同样的事情。
所以如果你想 "query" 那么它会在外部进行评估。如果您想处理一个值 "within the document",那么您必须在 $project
或 $group
流水线阶段进行。
从 mongodb 3.6 开始,您可以通过 $expr 在 $match 阶段使用 $subtract。这是文档:https://docs.mongodb.com/manual/reference/operator/query/expr/
我能够通过此 $expr 和 mongodb 4.2 中名为 $$NOW 的新系统变量获得您所描述的查询。这是我的查询,它为我提供了过去 4 小时内创建的订单:
[
{ $match:
{ $expr:
{ $gt: [
"$_created_at",
{ $subtract: [ "$$NOW", 4 * 60 * 60 * 1000] } ]
}
}
}
]
我正在创建一个 mongo 聚合查询,它在我的 $match 块中使用 $subtract 运算符。正如下面这些代码中所解释的。
此查询无效:
db.coll.aggregate(
[
{
$match: {
timestamp: {
$gte: {
$subtract: [new Date(), 24 * 60 * 60 * 1000]
}
}
}
},
{
$group: {
_id: {
timestamp: "$timestamp"
},
total: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
timestamp: "$_id.timestamp",
total: "$total",
}
},
{
$sort: {
timestamp: -1
}
}
]
)
但是,第二个查询有效:
db.coll.aggregate(
[
{
$match: {
timestamp: {
$gte: new Date(new Date() - 24 * 60 * 60 * 1000)
}
}
},
{
$group: {
_id: {
timestamp: "$timestamp"
},
total: {
$sum: 1
}
}
},
{
$project: {
_id: 0,
timestamp: "$_id.timestamp",
total: "$total",
}
},
{
$sort: {
timestamp: -1
}
}
]
)
我需要在我的 $match
块上使用 $subtract
,所以我不能使用最后一个查询。
$subtract
运算符是投影运算符。它仅在 $project
步骤期间可用。所以你的选择是:
- (不推荐)在您的$match-step 之前添加一个$project-step 以转换所有文档的
timestamp
字段以用于后续的match-step。我不建议您这样做,因为此操作需要对数据库中的每个文档执行,并且会阻止数据库在时间戳字段上使用索引,因此可能会消耗大量性能。 - (推荐)在应用程序的 shell / 中生成要匹配的日期。生成一个新的 Date() 对象,将其存储在一个变量中,从中减去 24 小时并使用该变量执行第二次查询。
好吧,你不能那样做,你也不打算那样做。另一件有效的事情是你对 "need" 说要这样做,但实际上你真的没有这样做。
几乎所有一般 aggregation operators outside of the pipeline operators are really only valid within a $project
or a $group
流水线阶段。主要在 $project
内,但肯定不在其他人内。
一个$match
pipeline is really the same as a general "query" operation, so the only things valid in there are the query operators.
至于您的 "need" 的情况,在聚合管道内提交的任何 "value",特别是在 $match
内提交的任何 "value" 都需要在实际管道之外进行评估,然后再BSON表示被发送到服务器。
唯一的例外是文档中定义变量的符号,特别是 "fieldnames" 这样的 "$fieldname"
,然后才真正出现在 $project
或 $group
中。所以这意味着 "refers" 到文档的现有值,这是在任何类型的 "query" 文档表达式中无法完成的事情。
如果您需要使用文档中另一个字段的值,那么您首先使用 $project
进行计算,如:
db.collection.aggregate([
{ "$project": {
"fieldMath": { "$subtract": [ "$fieldOne", "$fieldTwo" ] }
}},
{ "$match": { "fieldMath": { "$gt": 2 } }}
])
出于任何其他目的,您确实想要评估管道的价值 "outside"。
以上回答了您提出的问题,但这回答了您没有提出的问题。
您的管道没有任何意义,因为单独对 "timestamp" 进行分组不太可能对任何内容进行分组,因为这些值的精度为毫秒,而且最多可能不会超过几个对于非常活跃的系统。
您似乎正在寻找要按 "day" 分组的数学运算,您可以这样做:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$timestamp", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$timestamp", new Date(0) ] },
1000 * 60 * 60 * 24
]}
]
},
"total": { "$sum": "$total" }
}}
])
那 "rounds" 你的时间戳值到一天,并且有更好的机会 "aggregating" 比你本来拥有的东西。
或者您可以使用 "date aggregation operators" 与复合键做同样的事情。
所以如果你想 "query" 那么它会在外部进行评估。如果您想处理一个值 "within the document",那么您必须在 $project
或 $group
流水线阶段进行。
从 mongodb 3.6 开始,您可以通过 $expr 在 $match 阶段使用 $subtract。这是文档:https://docs.mongodb.com/manual/reference/operator/query/expr/
我能够通过此 $expr 和 mongodb 4.2 中名为 $$NOW 的新系统变量获得您所描述的查询。这是我的查询,它为我提供了过去 4 小时内创建的订单:
[
{ $match:
{ $expr:
{ $gt: [
"$_created_at",
{ $subtract: [ "$$NOW", 4 * 60 * 60 * 1000] } ]
}
}
}
]