MongoDB - 查询数组的最后一个元素?

问题描述 投票:0回答:12

我知道 MongoDB 支持语法

find{array.0.field:"value"}
,但我特别想对数组中的最后一个元素执行此操作,这意味着我不知道索引。 有某种操作员可以做到这一点,还是我运气不好?

编辑:为了澄清,我希望 find() 仅返回数组最后一个元素中的字段与特定值匹配的文档。

arrays mongodb mongoose mongodb-query spring-data-mongodb
12个回答
42
投票

在 3.2 中这是可能的。第一个项目使 myField 仅包含最后一个元素,然后在 myField 上进行匹配。

db.collection.aggregate([
   { $project: { id: 1, myField: { $slice: [ "$myField", -1 ] } } },
   { $match: { myField: "myValue" } }
]);

34
投票

您可以使用 $expr(3.6 mongo 版本运算符)在常规查询中使用聚合函数。

比较

query operators
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);

31
投票

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" } }
])

20
投票

使用$切片

db.collection.find( {}, { array_field: { $slice: -1 } } )

编辑: 您可以利用

{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
查找匹配项。

但它不会准确地给出您正在寻找的内容。我认为这在 mongoDB 中还不可能。


15
投票

我在官方 Mongo Google 群组这里发帖,并得到了他们工作人员的答复。 看来我正在寻找的东西是不可能的。 我将使用不同的模式方法。


12
投票

版本3.6使用聚合来实现相同的效果。

db.getCollection('deviceTrackerHistory').aggregate([
   {
     $match:{clientId:"12"}
   },
   {
     $project:
      {
         deviceId:1,
         recent: { $arrayElemAt: [ "$history", -1 ] }
      }
   }
])

6
投票

您可以在每次 $position: 0

 时使用 
$push
,然后始终查询 
array.0
来获取最近添加的元素。当然,您将无法获得新的“最后”元素。


6
投票

不确定性能,但这对我来说很有效:

db.getCollection('test').find(
  {
    $where: "this.someArray[this.someArray.length - 1] === 'pattern'"
  }
)

6
投票

您可以使用聚合来解决这个问题。

model.aggregate([
    {
      $addFields: {
        lastArrayElement: {
          $slice: ["$array", -1],
        },
      },
    },
    {
      $match: {
        "lastArrayElement.field": value,
      },
    },
  ]);

快速解释。

aggregate
创建一个按顺序执行的操作管道,这就是它采用数组作为参数的原因。首先我们使用
$addFields
管道阶段。这是 3.4 版本中的新功能,基本上意味着:保留文档的所有现有字段,但还要添加以下内容。在我们的例子中,我们添加
lastArrayElement
并将其定义为数组中的最后一个元素,称为
array
。接下来我们执行
$match
管道阶段。其输入是前一阶段的输出,其中包括我们新的
lastArrayElement
字段。在这里,我们说我们只包含其字段
field
具有值
value
的文档。

请注意,生成的匹配文档将包括

lastArrayElement
。如果由于某种原因你真的不想要这个,你可以在
$project
之后添加一个
$match
管道阶段来删除它。


0
投票

对于答案,请使用

$arrayElemAt
,如果我想要 orderNumber:“12345”并且最后一个元素的值 $gt 大于“value”?如何制作$expr?谢谢!

对于嵌入式数组 - 使用带有点符号的

$arrayElemAt
表达式来投影最后一个元素。

 db.col.find({$expr: {$gt: [{"$arrayElemAt": ["$array.field", -1]}, value]}})

0
投票

db.collection.aggregate([
  {
    $match: { 
      $and: [ 
        { $expr: { $eq: [{ "$arrayElemAt": ["$fieldArray.name", -1] }, "value"] } }, 
        { $or: [] }
      ] 
    } 
  }
]);


0
投票
db.collection.find({
  $expr: {
    $eq: [
      {
        $arrayElemAt: ['$array.andOrNestedProp', -1],
      },
      value
    ]
  }
});

value
是一个变量。
$array
是属性(您要定位的数组),
.andOrNestedProp
是可选的(如果它是子文档数组)。如果您正在处理一系列简单的事情,您只需执行
$array
位即可。

© www.soinside.com 2019 - 2024. All rights reserved.