猫鼬计算平均值

时间:2016-03-04 07:52:06

标签: node.js mongodb

我有以下猫鼬模型:

var MobileAppSchema = mongoose.Schema({
    identifier: String,
    ...
});

var RecordingSchema = mongoose.Schema({
  ... ,
  app: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'MobileApp'
  },
  length: Number,
  ...
});

现在我得到一些MobileAppSchema的记录,我希望得到所有RecordingSchemas,其中Recording.app等于我的一个MobileApps。对于所有获取的文档,我想获得Recording.length的平均值。

我当前的方法有效,但是我想直接与mongoose查询聚合,而不是之后。

目前的实施:

exports.averageTimeSpentForAppIdentifier = function(appIdentifier, done) {
    mobileAppsForAppIdentifier(appIdentifier, function(err, mobileApps) {
        if(err) {
            return done(err);
        }

        var appIds = mobileApps.map(function(mobileApp) {return mobileApp._id;});

        Recording.find({
            'app': { $in: appIds}}, function(err, recordings) {
            if(err) {
                return done(err);
            }

            if(!recordings || recordings.length == 0) {
                return done(null, 0);
            }

            var average = recordings
            .map(function(recording,i,arr) {
                return recording.length/arr.length
            })
            .reduce(function(a,b) {
                return a + b
            });

            done(null, average);
        });
    });
};

1 个答案:

答案 0 :(得分:2)

汇总框架可供您使用。运行以下管道将为您提供所需的结果。它使用 $match 管道作为过滤掉进入聚合的文档的初始步骤 没有制定mobileApps id的给定标准的管道。

后面的 $group 运算符用于主聚合,即使用 $avg 累加器运算符计算分组文档的平均长度:

exports.averageTimeSpentForAppIdentifier = function(appIdentifier, done) {
    mobileAppsForAppIdentifier(appIdentifier, function(err, mobileApps) {
        if(err) {
            return done(err);
        }

        var appIds = mobileApps.map(function(mobileApp) {return mobileApp._id;}),
            pipeline = [
                {"$match": { "app": { $in: appIds } } },
                {
                    "$group": {
                        "_id": null,
                        "average": { "$avg": "$length" }
                    }
                }
            ];

        Recording.aggregate(pipeline)
                .exec(function (err, result){
                    if(err) {
                        return done(err);
                    }
                    done(null, result[0].average);
                })

        // Or using the fluent pipeline builder API         
        Recording.aggregate()
                .match({ "app": { $in: appIds } })
                .group({ "_id": null, "average": { "$avg": "$length" }})
                .exec(function (err, result){
                    if(err) {
                        return done(err);
                    }
                    done(null, result[0].average);
                });       
    });
};
相关问题