将文档数组大小与其他文档字段进行比较

时间:2016-10-30 18:12:07

标签: mongodb mongodb-query aggregation-framework

该文件可能如下:

{
  _id: 'abc',
  programId: 'xyz',
  enrollment: 'open',
  people: ['a', 'b', 'c'],
  maxPeople: 5
}

我需要返回所有注册为openpeople的长度小于maxPeople

的文档

我让它与$where

一起使用
const
  exists = ['enrollment', 'maxPeople', 'people'],
  query = _.reduce(exists, (existsQuery, field) => {
    existsQuery[field] = {'$exists': true}; return existsQuery; 
  }, {});

query['$and'] = [{enrollment: 'open'}];
query['$where'] = 'this.people.length<this.maxPeople';
return db.coll.find(query, {fields: {programId: 1, maxPeople: 1, people: 1}});

但我可以通过聚合来做到这一点,为什么会更好?

此外,如果聚合更好/更快,我不明白如何将上述查询转换为使用聚合。我坚持:

db.coll.aggregate([
  {$project: {ab: {$cmp: ['$maxPeople','$someHowComputePeopleLength']}}},
  {$match: {ab:{$gt:0}}}
]);

更新

基于@chridam回答,我能够实现这样的解决方案,请注意$and中的$match,对于那些需要类似查询的人:

  return Coll.aggregate([
    {
      $match: {
        $and: [
          {"enrollment": "open"},
          {"times.start.dateTime": {$gte: new Date()}}
        ]
      }
    },
    {
      "$redact": {
        "$cond": [
          {"$lt": [{"$size": "$students" }, "$maxStudents" ] },
          "$$KEEP",
          "$$PRUNE"
        ]
      }
    }
  ]);

2 个答案:

答案 0 :(得分:3)

在这种情况下,聚合框架中的 $redact 管道运算符应该适合您。这将以递归方式下降到文档结构中,并根据每个级别的指定条件的评估执行一些操作。这个概念可能有点棘手,但基本上操作符允许您使用 $cond 运算符来处理逻辑条件并使用特殊操作 $$KEEP “保留”逻辑条件为真的文档或 $$PRUNE 以“删除”条件为false的文档。

此操作类似于具有 $project 管道,该管道选择集合中的字段并创建一个新字段,其中包含逻辑条件查询的结果,然后是后续的 $match ,但 $redact 使用单个管道阶段,该阶段根据查看数据所需的访问权限限制结果集的内容,效率更高

要对enrollment已打开且people的长度小于maxPeople的所有文档运行查询,请添加 $redact 阶段如下::

db.coll.aggregate([
    { "$match": { "enrollment": "open" } },
    { 
        "$redact": {
            "$cond": [
                { "$lt": [ { "$size": "$people" }, "$maxPeople" ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

答案 1 :(得分:1)

你可以这样做:

  • 1 $project创建一个新字段,其中包含peoplemaxPeople
  • 数组大小的比较结果
  • 1 $match与之前的比较结果相符&amp; enrollmentopen

查询是:

db.coll.aggregate([{
    $project: {
        _id: 1,
        programId: 1,
        enrollment: 1,
        cmp: {
            $cmp: ["$maxPeople", { $size: "$people" }]
        }
    }
}, {
    $match: {
        $and: [
            { cmp: { $gt: 0 } },
            { enrollment: "open" }
        ]
    }
}])