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

Jos*_*air 31 arrays mongoose mongodb mongodb-query spring-data-mongodb

我知道MongoDB支持语法find{array.0.field:"value"},但我特别想为数组中的最后一个元素执行此操作,这意味着我不知道索引.是否有某种操作员,或者我运气不好?

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

小智 24

在3.2中,这是可能的.第一个项目,以便myField只包含最后一个元素,然后匹配myField.

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

  • 在3.2中有$ arrayElemAt运算符,它与负索引一起使用.所以这可以是`{$ project:{id:1,myField:{$ arrayElemAt:["$ myField",-1]}}}`.我不知道只有一个元素的切片是否同样有效 (3认同)

Kau*_*hal 14

使用$ slice.

db.collection.find( {}, { array_field: { $slice: -1 } } )
Run Code Online (Sandbox Code Playgroud)

编辑:您可以利用 { <field>: { $elemMatch: { <query1>, <query2>, ... } } }来查找匹配项.

但它不会给出你想要的东西.我不认为mongoDB中有可能.

  • 请记住,'$ slice'返回一个数组,而'$ arrayElemAt'返回一个文档(相同的sintax)。 (2认同)

Jos*_*air 13

我在这里发布了官方的Mongo Google小组,并得到了他们的工作人员的答复.似乎我正在寻找的是不可能的.我将使用不同的模式方法.


Xav*_*hot 12

从 开始Mongo 4.4,聚合运算符$last可用于访问数组的最后一个元素:


例如,在find查询中:

// { "myArray": ["A", "B", "C"] }
// { "myArray": ["D"] }
db.collection.find({ $expr: { $eq: [{ $last: "$myArray" }, "C"] } })
// { "myArray": ["A", "B", "C"] }
Run Code Online (Sandbox Code Playgroud)

或在aggregation查询中:

db.collection.aggregate([
  { $addFields: { last: { $last: "$myArray" } } },
  { $match: { last: "C" } }
])
Run Code Online (Sandbox Code Playgroud)

  • 这就是2021年的正确答案! (3认同)

use*_*814 11

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

比较query operatorsVS aggregation comparison operators.

对于标量数组

db.col.find({$expr: {$gt: [{$arrayElemAt: ["array", -1]}, value]}})
Run Code Online (Sandbox Code Playgroud)

对于嵌入式数组 - 使用$arrayElemAt带点符号的表达式来投影最后一个元素.

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

春天的@Query代码

@Query("{$expr:{$gt:[{$arrayElemAt:[\"array\", -1]}, ?0]}}")
ReturnType MethodName(ArgType arg);
Run Code Online (Sandbox Code Playgroud)


KAR*_*N.A 11

3.6 版使用聚合来实现相同的功能。

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


Ram*_*tov 7

不确定性能,但这适合我:

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

  • $where 很慢,因为它运行 javascript (2认同)

Jon*_*ist 6

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

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

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

请注意,生成的匹配文档将包括lastArrayElement. 如果由于某种原因你真的不想要这个,你可以$project在之后添加一个管道阶段$match来删除它。


Ric*_*cky 5

你可以使用$position: 0,只要你$push,然后总是查询array.0以获得最近添加的元素.当然,你将无法获得新的"最后"元素.