检查数组中的最后一个元素是否符合条件

时间:2015-08-07 22:51:20

标签: mongodb mongoose mongodb-query aggregation-framework

我的mongodb文档中有一组数字,需要检查该数组中的最后一个数字是否符合我的条件。

我的文档存储方式如下:

  {
    name: String,
    data: {
      dates: Array,
      numbers: Array
    }
  }

我需要检查numbers中的最后一个数字是否位于“另外两个数字之间。”

有关如何执行此操作的任何建议将不胜感激。

2 个答案:

答案 0 :(得分:2)

现在,最有效的方法是使用$where的JavaScript评估,因为您可以简单地找到最后一个数组元素的值并以编程方式对其进行测试。

使用示例文档:

{ "a": [1,2,3] },
{ "a": [1,2,4] },
{ "a": [1,2,5] }

并查询:

db.collection.find(function() { var a = this.a.pop(); return ( a > 2 ) & ( a < 5 ) })

或简单地将$where作为评估字符串显示:

Model.find(
    { 
        "$where": "var a = this.a.pop(); return ( a > 2 ) && ( a < 5 )"
    },
    function(err,results) {
        // handling here
    }
);

这是一种非常简单的方法,并且在为“非规范化”和处理数组创建的聚合框架中没有诸如$unwind之类的“开销”。那里效率不高。

然而,在“未来”中,。正如开发版本中目前可用的那样,聚合框架有一个 $slice 运算符。此运算符将允许轻松访问“最后”数组元素以进行测试。

由于聚合框架运算符在“本机代码”而不是要解释的JavaScript中,因此单个管道阶段变得比JavaScript表单更有效。虽然这样做的列表在提交时看起来更长:

db.collection.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$anyElementTrue": {
          "$map": {
            "input": { "$slice": ["$a",-1] },
            "as": "el",
            "in":{
              "$and": [
                { "$gt": [ "$$el", 2 ] },
                { "$lt": [ "$$el", 5 ] }
              ]
            }
          }
        }
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

已存在的$redact运算符用于在此处使用比较表达式“逻辑过滤”。根据{{​​1}}匹配条件,它可以分别从结果中“保留”或“修剪”文档。

它的聚合框架形式中的true/false运算符本身仍然会非常接近地返回一个数组,尽管在这种情况下是单个元素数组。这就是$map用于将每个元素“转换”为$slice条件的原因,而$anyElementTrue运算符将“数组”缩减为$cond所预期的单数响应

所以当它发布时,那将是最有效的方法。但在此之前,坚持使用JavaScript,因为它是目前评估的最快方式。

这两个查询表单只返回示例中的前两个文档:

true/false

答案 1 :(得分:0)

MongoDB aggregate可能是一种可行的方法。假设文档中的名称字段是唯一的。

如果您有样本文件。

   {
     name: "allen",
     data: {
      dates: ["2015-08-08"],
      numbers: [20, 21, 22, 23]
     }
   }

以下代码用于检查。当 db.collection.aggregate()方法返回游标,然后我们可以使用游标hasNext来确定最后一个数字是否位于给定的两个数字之间。

var result = db.last_one.aggregate(
 [
   {
      // deconstruct the array field numbers
      $unwind: "$data.numbers"
   },
   { 
     $group: { 
      _id: "$name", 
      // lastNumber is 23 in this case 
      lastNumber: { $last: "$data.numbers" }
     } 
   },
   {
    $match: {
       lastNumber: { $gt: num1, $lt: num2 }
    }
   }
 ]  
).hasNext()

if (result) print("matched"); else print("not matched")

例如,如果num1为22,num2为24,则匹配结果;如果num1为21,num2为22,则结果不匹配。

但实际上,名字上的小组并不是一个好主意。如果您的文档具有唯一的ObjectId,那么我们就可以对该_id进行分组。