限制推送到MongoDB聚合中数组的对象数

30byixjq  于 2022-12-22  发布在  Go
关注(0)|答案(1)|浏览(187)

我一直试图找到一种方法来限制在MongoDB集合上使用"aggregate"时推送到数组中的对象的数量,我有一个学生集合--**每个学生都有这些相关的键:**这个学期的班级号(只有一个值),班级百分比(如果注册了班级,则存在,否则为空),班级当前分数(如果注册了班级,则〉0,否则为-0),总平均分(GPA),最高分
我需要将每门课上从未失败过的所有学生分组到一个包含GPA高于80的学生的数组中,另一个包含GPA不高于80的学生的数组中,按他们在这门课上的分数排序。
这是我的疑问:

db.getCollection("students").aggregate([
{"$match": {
    "class_number": 
        {"$in": [49, 50, 16]},
    "grades.curr_class.percentile": 
        {"$exists": true},
    "grades.min": {"$gte": 80},
    }},
    {"$sort": {"grades.curr_class.score": -1}},
    {"$group": {"_id": "$class_number", 
                "studentsWithHighGPA": 
                    {"$push": 
                        {"$cond": [{"$gte": ["$grades.gpa", 80]},
                        {"id": "$_id"},
                        "$$REMOVE"]
                        }
                    },
                 "studentsWithoutHighGPA":
                 {"$push": 
                        {"$cond": [{"$lt": ["$grades.gpa", 80]},
                        {"id": "$_id"},
                        "$$REMOVE"]
                        }, 
                    },
                    }, 
                },
])

我所要做的是限制每个数组中的学生数量,我只希望每个数组中的前16名,但我不知道该如何处理。
先谢了!
我试过在不同的变体中使用limit,也试过slice,但似乎都不起作用。

pkwftd7m

pkwftd7m1#

我不认为mongodb提供的操作符可以在$group stage中应用限制。
您可以使用$accumulator,但这需要启用服务器端脚本,并且可能会影响性能。
在整个分组中,将学生的GPA限制在16分以下可能类似于:

"studentsWithHighGPA": {
        "$accumulator": {
          init: "function(){
                     return {combined:[]};
          }",
          accumulate: "function(state, id, score){
                              if (score >= 80) {
                                    state.combined.push({_id:id, score:score})
                              };
                              return {combined:state.combined.slice(0,16)}
          }",
          accumulateArgs: [ "$_id", "$grades.gpa"],
          merge: "function(A,B){
                     return {combined: 
                              A.combined.concat(B.combined).sort(
                                    function(SA,SB){
                                           return (SB.score - SA.score)
                                    })
                            }
          }",
          finalize: "function(s){
               return s.combined.slice(0,16).map(function(A){
                  return {_id:A._id}
               })
          }",
          lang: "js"
        }
      }

请注意,评分也会一直进行到最后,以便可以正确地组合来自不同碎片的部分结果集。

相关问题