MongoDB - 查询数组的最后一个元素?
MongoDB - Query on the last element of an array?
我知道 MongoDB 支持语法 find{array.0.field:"value"}
,但我特别想对数组中的最后一个元素执行此操作,这意味着我不知道索引。是否有某种运算符可以做到这一点,还是我运气不好?
编辑:为了澄清,我希望 find() 仅 return 记录数组最后一个元素中的字段与特定值匹配的情况。
使用$slice.
db.collection.find( {}, { array_field: { $slice: -1 } } )
编辑:
你可以利用
{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
找到匹配项。
但它不会准确提供您要查找的内容。我不认为这在 mongoDB 中是可能的。
我在官方MongoGoogle群here发帖,得到了他们工作人员的回复。看来我正在寻找的是不可能的。我将使用不同的模式方法。
您可以在 $push
时使用 $position: 0
,然后始终查询 array.0
以获取最近添加的元素。当然,您将无法获得新的 "last" 元素。
不确定性能,但这对我来说效果很好:
db.getCollection('test').find(
{
$where: "this.someArray[this.someArray.length - 1] === 'pattern'"
}
)
在 3.2 中这是可能的。首先项目使 myField 只包含最后一个元素,然后在 myField 上进行匹配。
db.collection.aggregate([
{ $project: { id: 1, myField: { $slice: [ "$myField", -1 ] } } },
{ $match: { myField: "myValue" } }
]);
您可以使用$expr(3.6 mongo版本运算符)在常规查询中使用聚合函数。
比较query operators
vs aggregation comparison operators
.
对于标量数组
db.col.find({$expr: {$gt: [{$arrayElemAt: ["$array", -1]}, value]}})
对于嵌入式数组 - 使用带点符号的 $arrayElemAt
表达式投影最后一个元素。
db.col.find({$expr: {$gt: [{"$arrayElemAt": ["$array.field", -1]}, value]}})
Spring@Query
代码
@Query("{$expr:{$gt:[{$arrayElemAt:[\"$array\", -1]}, ?0]}}")
ReturnType MethodName(ArgType arg);
版本 3.6 使用聚合来实现相同的目的。
db.getCollection('deviceTrackerHistory').aggregate([
{
$match:{clientId:"12"}
},
{
$project:
{
deviceId:1,
recent: { $arrayElemAt: [ "$history", -1 ] }
}
}
])
对于答案使用 $arrayElemAt
,如果我想要 orderNumber:"12345" 和最后一个元素的值 $gt 而不是 "value"?如何制作$expr?谢谢!
对于嵌入式数组 - 使用带点符号的 $arrayElemAt
表达式投影最后一个元素。
db.col.find({$expr: {$gt: [{"$arrayElemAt": ["$array.field", -1]}, value]}})
从 Mongo 4.4
开始,聚合运算符 $last
可用于访问数组的最后一个元素:
例如,在 find
查询中:
// { "myArray": ["A", "B", "C"] }
// { "myArray": ["D"] }
db.collection.find({ $expr: { $eq: [{ $last: "$myArray" }, "C"] } })
// { "myArray": ["A", "B", "C"] }
或在 aggregation
查询中:
db.collection.aggregate([
{ $addFields: { last: { $last: "$myArray" } } },
{ $match: { last: "C" } }
])
您可以使用聚合解决此问题。
model.aggregate([
{
$addFields: {
lastArrayElement: {
$slice: ["$array", -1],
},
},
},
{
$match: {
"lastArrayElement.field": value,
},
},
]);
快速解释。 aggregate
创建一个动作管道,按顺序执行,这就是它采用数组作为参数的原因。首先我们使用 $addFields
流水线阶段。这是 3.4 版本新增的,基本意思是:保留文档的所有现有字段,但还要添加以下内容。在我们的例子中,我们添加 lastArrayElement
并将其定义为名为 array
的数组中的最后一个元素。接下来我们执行 $match
流水线阶段。此输入是前一阶段的输出,其中包括我们新的 lastArrayElement
字段。这里我们说我们只包含其字段 field
的值为 value
.
的文档
请注意,生成的匹配文档将包括 lastArrayElement
。如果出于某种原因你真的不想要这个,你可以在 $match
之后添加一个 $project
管道阶段来删除它。
我知道 MongoDB 支持语法 find{array.0.field:"value"}
,但我特别想对数组中的最后一个元素执行此操作,这意味着我不知道索引。是否有某种运算符可以做到这一点,还是我运气不好?
编辑:为了澄清,我希望 find() 仅 return 记录数组最后一个元素中的字段与特定值匹配的情况。
使用$slice.
db.collection.find( {}, { array_field: { $slice: -1 } } )
编辑:
你可以利用
{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
找到匹配项。
但它不会准确提供您要查找的内容。我不认为这在 mongoDB 中是可能的。
我在官方MongoGoogle群here发帖,得到了他们工作人员的回复。看来我正在寻找的是不可能的。我将使用不同的模式方法。
您可以在 $push
时使用 $position: 0
,然后始终查询 array.0
以获取最近添加的元素。当然,您将无法获得新的 "last" 元素。
不确定性能,但这对我来说效果很好:
db.getCollection('test').find(
{
$where: "this.someArray[this.someArray.length - 1] === 'pattern'"
}
)
在 3.2 中这是可能的。首先项目使 myField 只包含最后一个元素,然后在 myField 上进行匹配。
db.collection.aggregate([
{ $project: { id: 1, myField: { $slice: [ "$myField", -1 ] } } },
{ $match: { myField: "myValue" } }
]);
您可以使用$expr(3.6 mongo版本运算符)在常规查询中使用聚合函数。
比较query operators
vs aggregation comparison operators
.
对于标量数组
db.col.find({$expr: {$gt: [{$arrayElemAt: ["$array", -1]}, value]}})
对于嵌入式数组 - 使用带点符号的 $arrayElemAt
表达式投影最后一个元素。
db.col.find({$expr: {$gt: [{"$arrayElemAt": ["$array.field", -1]}, value]}})
Spring@Query
代码
@Query("{$expr:{$gt:[{$arrayElemAt:[\"$array\", -1]}, ?0]}}")
ReturnType MethodName(ArgType arg);
版本 3.6 使用聚合来实现相同的目的。
db.getCollection('deviceTrackerHistory').aggregate([
{
$match:{clientId:"12"}
},
{
$project:
{
deviceId:1,
recent: { $arrayElemAt: [ "$history", -1 ] }
}
}
])
对于答案使用 $arrayElemAt
,如果我想要 orderNumber:"12345" 和最后一个元素的值 $gt 而不是 "value"?如何制作$expr?谢谢!
对于嵌入式数组 - 使用带点符号的 $arrayElemAt
表达式投影最后一个元素。
db.col.find({$expr: {$gt: [{"$arrayElemAt": ["$array.field", -1]}, value]}})
从 Mongo 4.4
开始,聚合运算符 $last
可用于访问数组的最后一个元素:
例如,在 find
查询中:
// { "myArray": ["A", "B", "C"] }
// { "myArray": ["D"] }
db.collection.find({ $expr: { $eq: [{ $last: "$myArray" }, "C"] } })
// { "myArray": ["A", "B", "C"] }
或在 aggregation
查询中:
db.collection.aggregate([
{ $addFields: { last: { $last: "$myArray" } } },
{ $match: { last: "C" } }
])
您可以使用聚合解决此问题。
model.aggregate([
{
$addFields: {
lastArrayElement: {
$slice: ["$array", -1],
},
},
},
{
$match: {
"lastArrayElement.field": value,
},
},
]);
快速解释。 aggregate
创建一个动作管道,按顺序执行,这就是它采用数组作为参数的原因。首先我们使用 $addFields
流水线阶段。这是 3.4 版本新增的,基本意思是:保留文档的所有现有字段,但还要添加以下内容。在我们的例子中,我们添加 lastArrayElement
并将其定义为名为 array
的数组中的最后一个元素。接下来我们执行 $match
流水线阶段。此输入是前一阶段的输出,其中包括我们新的 lastArrayElement
字段。这里我们说我们只包含其字段 field
的值为 value
.
请注意,生成的匹配文档将包括 lastArrayElement
。如果出于某种原因你真的不想要这个,你可以在 $match
之后添加一个 $project
管道阶段来删除它。