mongodb聚合:平均和排序

时间:2015-01-29 20:41:51

标签: node.js mongodb mongoose aggregation-framework

我是一个新手,并且有一个mongodb聚合问题。我用猫鼬。

var SubjectScore = new Schema({
    name: {type:String, required:true}, //math, science, history, ...
    score: {type:Number, required:true } // 95, 85, 77,....
});

var Subject = new Schema({
    year: Number,  //2012, 2013, 2014
    subjectScore : [SubjectScore]
});

var StudentSchema = new Schema({
    name: String,
    subject: [Subject], //array length varies for each student
    profile: String,
});

所以,输入数据是这样的。

{ _id: 54c921aaa7918d4e4a8c7e51, 
  name: John, 
  profile: "He is nice",
  subject: [{ year: 2010, 
              subjectScore: [{ name:"history" score:66},
                            { name:"math", score:65},
                            { name:"science", score:87}] }]
            },{ year: 2011, 
              subjectScore: [{ name:"history" score:75},
                            { name:"math", score:61},
                            { name:"science", score:92}] }]
            },{ year: 2012, 
              subjectScore: [{ name:"history" score:83},
                            { name:"math", score:82},
                            { name:"science", score:86}] }]
            },{ year: 2013, 
              subjectScore: [{ name:"history" score:77},
                            { name:"math", score:99},
                            { name:"science", score:71}] }]
            }]
}

我想得到的最终结果如下。

[
{ _id: "54c921aaa7918d4e4a8c7e51", 
   name: "John"
   profile: "He is nice",
   avgScore: [ 
              {name: "math", score: 77}, 
              {name:"history", score:78},
              {name:"science", score:86}  ]
   totalAvg: 82
},
{ _id: "54c921aaa7918d4e4a8c7e5b", 
   name: "Mary"
   profile: "She is kind",
   avgScore: [ 
              {name: "math", score: 67}, 
              {name:"history", score:99},
              {name:"science", score:96}  ]
   totalAvg: 82
},
{ _id: "54c921aaa7918d4e4a8c7e56", 
   name: "Jane"
   profile: "She is smart",
   avgScore: [ 
              {name: "math", score: 99}, 
              {name:"history", score:99},
              {name:"science", score:99}  ],
   totalAvg: 99
}
 ..... // 7 more student for first page result
]

我试过了,但我无法获得名称,个人资料的字段。所以我需要额外的查询来获取名称和配置文件字段并再次排序。

  {$project:{subject:1}},
  {$unwind:"$subject"},
  {$unwind:"$subject.subjectScore"},
  {$group:{_id:{studentId:"$_id", subjectName:"$subject.subjectScore.name"},
           avgScore:{$avg: "$subject.subjectScore.score"}}},
  {$group:{_id:"$_id.studentId", 
           avgScore:{$push: {name:"$_id.subjectName", score:"$avgScore"}}, 
           totalAvg:{$avg:"$avgScore"}}},
  {$sort:{totalAvg:-1}},
  {$limit:10} // for first page (students per page : 10)
  1. 我想知道如何保留聚合不需要的字段,但需要显示结果。如果不可能,我是否需要对我想要的结果进行额外查询?

  2. 考虑到性能,还有其他方法可以获得此结果吗?

  3. 我已经花了几天时间来完成这项工作和谷歌搜索,但没有得到答案。请帮帮我。

    谢谢。

1 个答案:

答案 0 :(得分:1)

您在第一次操作中丢失了信息,因为$project仅发送subject密钥的值。

保持字段值不受聚合计算(nameprofile)影响的操作与$first一致。它只会获取该字段的第一个值,该值应与其余字段相同。

{ $unwind: "$subject" },
{ $unwind: "$subject.subjectScore" },
{ $group: { _id: { sId: "$_id", subjectName: "$subject.subjectScore.name" },
            avgScore: { $avg: "$subject.subjectScore.score" },
            name: { $first: "$name" },
            profile: { $first: "$profile" } } },
{ $group: { _id: "$_id.sId",
            name: { $first: "$name" },
            profile: { $first: "$profile" },
            avgScore: { $push: { name: "$_id.subjectName", score: "$avgScore" } },
            totalAvg: { $avg: "$avgScore" } } }
{ $sort: { totalAvg: -1 } }, // this is sorting desc, but sample is asc?
{ $limit: 10 }