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

时间:2015-02-23 18:03:21

标签: arrays mongodb mongoose mongodb-query spring-data-mongodb

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

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

10 个答案:

答案 0 :(得分:17)

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

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

答案 1 :(得分:13)

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

答案 2 :(得分:11)

使用 $ slice

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

编辑: 你可以利用  { <field>: { $elemMatch: { <query1>, <query2>, ... } } }找到匹配。

但它不能准确地给出你想要的东西。我不认为mongoDB中有可能。

答案 3 :(得分:7)

不确定性能,但这对我很有用:

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

答案 4 :(得分:7)

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

比较query operatorsaggregation comparison operators

对于标量数组

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

对于嵌入式数组 - 使用带有点表示法的$arrayElemAt表达式来投影最后一个元素。

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

Spring @Query代码

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

答案 5 :(得分:5)

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

答案 6 :(得分:5)

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

答案 7 :(得分:4)

版本3.6 使用聚合来实现相同目标。

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

答案 8 :(得分:1)

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

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

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

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

答案 9 :(得分:0)

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

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

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