检索数组大小总和大于给定值的文档

时间:2017-05-28 09:19:39

标签: mongodb mongoose mongodb-query aggregation-framework

我有一个Mongoose Schema定义如下:

const hackathonSchema = new mongoose.Schema({
    hackathonId: {type: Number, required: true},
    uuid: {type: String, required: true},
    data: {type: Object, required: true},
    isPublished: {type: Boolean, default: false},
    organisers: [String],
    volunteers: [String],
    participants: [String],
    mentors: [String]
});

export default mongoose.model('Hackathon', hackathonSchema);

我想要检索所有的Hackathons 长度:

( organisers + volunteers + participants +mentors ) >= 500

或该问题的任何价值。

我找到了SO的答案,而不是Mongoose How to select where sum of fields is greater than a value in MongoDB

1 个答案:

答案 0 :(得分:1)

只需将尺寸加在一起:

使用$concatArrays

的MongoDB 3.4或更高版本
Model.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$gt": [
          { "$size": {
            "$concatArrays": [
              { "$ifNull": [ "$organisers", [] ]  },
              { "$ifNull": [ "$volunteers", [] ]  },
              { "$ifNull"; [ "$participants", [] ] },
              { "$ifNull": [ "$mentors", [] ] }
            ]
          } },
          500
        ]    
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$project": { "_id": 1 } }
],function(err,results) { 

})

或者在没有该运算符的早期版本中

Model.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$gt": [
          { "$add": [
            { "$size": { "$ifNull": [ "$organisers", [] ] } },
            { "$size": { "$ifNull": [ "$volunteers", [] ] } },
            { "$size": { "$ifNull": [ "$participants", [] ] } },
            { "$size": { "$ifNull": [ "$mentors", [] ] } }
          ]},
          500
        ]    
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$project": { "_id": 1 } }
],function(err,results) { 

})

在任何一种方法中,您都使用$redact作为集合中文档的逻辑过滤器。作为本地运营商,这是处理这种情况的最快方法。

在内部,它唯一的参数是$cond,它是一个“三元”操作(if / then / else)来评估和返回一个值。因此,当"if"条件的结果导致true"then"时,操作是$$KEEP文档,或者"else"$$PRUNE来自结果的文件。

基于版本的不同方法是:

  • $concatArrays为了制作一个“大”数组并将其返回$size

  • 或者在每个数组上使用$size并使用$add值来获得总数。

至于仅仅返回_id字段,那么添加$project阶段很简单,就像在常规查询投影中一样,您提供要返回的属性列表。在这种情况下,只有_id字段。

您可以首先使用$match向基本查询添加一些关于最小数组长度的假设,但这是一个假设,而不是绝对事实。

对于记录,您可以使用$where子句运行完全相同的东西,但由于此运算符使用JavaScript评估而不是作为聚合框架操作本机实现,因此它确实会对性能产生重大影响因为它运行得慢:

Model.find({ "$where": function() {
   return [
     ...this.organisers,
     ...this.volunteers,
     ...this.participants,
     ...this.mentors
   ].length > 500
}).select({ "_id": 1 }).exec(function(err,results) {
})

因此,与DSL形式的聚合流水线结构相比,它看起来“漂亮”,但性能损失并不值得。只有当MongoDB版本缺少$redact作为运算符时才应该执行此操作,这将在MongoDB 2.6之前。在这种情况下,您可能也应该出于其他原因更新MongoDB。