【问题标题】:MongoDB: How to count average of a nested arrayMongoDB:如何计算嵌套数组的平均值
【发布时间】:2017-09-04 02:52:51
【问题描述】:

我想通过获取 ID 和 NAME 的专用函数计算不同“课程”(“IABD”、NPAD”...)的平均“成绩” strong>(当然)作为集合文档中的参数,结构如下。

{
        "_id" : ObjectId("58e8ba731c9f5cc5bf605e27"),
        "ID" : 123457,
        "name" : "Stack",
        "surname" : "Overflow",
        "grades" : [
                {
                        "IABD" : [
                                2,
                                3,
                                4,
                                5
                        ]
                },
                {
                        "NPAD*" : [
                                3.5,
                                2.5
                        ]
                },
                {
                        "SIDB" : [
                                5,
                                3.5
                        ]
                },
                {
                        "NPAD" : [
                                5,
                                2
                        ]
                },
                {
                        "IABD" : [
                                4,
                                6
                        ]
                }
        ]
}

以下一项不起作用:

db.studenci.aggregate([ { $project: { courseAvg: { $avg: '$grades.NPAD'} } } ])

尝试从通过以下方式获取带有成绩的数组:

function avg(ID,course) { doc = db.collection.find({ID: ID}); doc1 = doc[0]; return doc1.grades[0]; }

但无法挖掘数组值来计算平均值...

一旦我得到想要进行简单 AVG 硬编码的值...

                var avg = 0 ;
                var summ = 0;
                for(var i = 0 ; i < numbers.length ; i++){
                    summ = summ + numbers[i]};
                    return summ
                    }   
                avg = summ / numbers.length;
                return avg;

期待您的回复。

【问题讨论】:

    标签: arrays mongodb nested average


    【解决方案1】:

    这不是一个优雅的解决方案(我不是 MongoDB 方面的专家),但这很有效(我在我的 mongo 上进行了本地测试):

    function avgByIdAndCourse(id, course){
    
    //THIS VARIABLE WILL STORE THE RESULT OF AVG
    var res;
    
    //REPLACE "N" WITH YOU COLLECTION NAME
    db.n.find(ObjectId(id)).forEach( function(doc) {
    
    //CREATE THE GRADES ARRAY
    var arr = doc.grades;
    
    //VARIABLE FOR AVG CALCULATION
    var count = 0;
    
    for(var i = 0; i < arr.length; i++){
        var obj = arr[i];
    
        //LOOP OVER GRADES KEY
        for(var key in obj){
    
        //IF THE COURSE MATCHES WITH OUR COURSE PARAMETER
        if(key == course){
            count = 0;
    
        //ARRAY OF VALUES OF COURSE
        var a = obj[key];
        for(var j = 0; j < a.length; j++){
            count += a[j];
        }
        // just a print for make sure it works ---> print(count/a.length);
    
        //STORE THE RESULT IN RES VARIABLE
        res = count/a.length;
        }
    
    }
      }
    
      //REQUIRED BY FOREACH CALLBACK(NOT SURE ABOUT THAT)
      db.n.save(doc);
     });
    
    //RETURN THE RESULT
    return res;
    }
    

    您可以尝试优化对密钥部分的循环(考虑到我们不需要循环访问密钥,我们可以通过尝试访问它来简单地检查该密钥是否存在)。

    如果你将它复制并粘贴到你的 shell 上,你可以这样测试它:

    var result = avgByIdAndCourse('PUTIDTOFINDHERE', 'COURSENAME');
    print(result);
    

    现在您应该看到该课程的平均值。

    希望对你有帮助。

    【讨论】:

    • 哇,它就像一个魅力!太感谢了!!我没想到它会变得如此先进。您能否告诉您有关如何将文档技术 ID 与作为对象属性存在的文档技术 ID 进行切换的任何建议? (示例中为 123457)
    • 我说过我不是专家,你应该向专家寻求推荐。要更改查询,您可以在 find 方法中编写类似这样的内容:{ID : id} 而不是 ObjectId(id)。如果对您有用,我可以请您投票并标记为解决方案吗?
    • 我很乐意,但是我还没有15个声望点,请问有没有办法克服它?
    • 对不起,我不知道。您应该看到 stackoverflow 文档
    猜你喜欢
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 2014-05-14
    相关资源
    最近更新 更多