如何在Mongoose中聚合嵌入文档中的字段

时间:2015-02-11 08:44:01

标签: node.js mongodb mongoose

覆盖范围模型。

var CoverageSchema = new Schema({
module : String,
source: String,
namespaces: [{
        name: String,
        types: [{
                name: String, 
                functions: [{
                        name: String, 
                        coveredBlocks: Number,
                        notCoveredBlocks: Number
                    }]
            }]
    }]
});

我需要在每个级别上使用coveredBlocks聚合:

*Module: {moduleBlocksCovered}, // SUM(blocksCovered) GROUP BY module, source
**Namespaces: [{nsBlocksCovered}] // SUM(blocksCovered) GROUP BY module, source, ns
****Types: [{typeBlocksCovered}] // SUM(blocksCovered) BY module, source, ns, type

如何在Mongoose中使用Coverage.aggregate获得此结果?

{
module: 'module1',
source: 'source1',
coveredBlocks: 7, // SUM of all functions in module
namespaces:[
     name: 'ns1',
     nsBlocksCovered: 7, // SUM of all functions in namespace
     types:[
     {
         name: 'type1',
         typeBlocksCovered: 7, // SUM(3, 4) of all function in type
         functions[
         {name: 'func1', blocksCovered: 3},
         {name:'func2', blocksCovered: 4}]
     }
     ]
]
}

1 个答案:

答案 0 :(得分:1)

我的想法是使用$ unwind解构所有内容,然后使用组和投影重新构建文档。

aggregate flow:

//deconstruct functions
unwind(namesapces) 
unwind(namespaces.types)
unwind(namespace.types.functions)
//cal typeBlocksCovered
group module&source ,ns,type to sum functions blocksCovered->typeBlocksCovered + push functions back to types
project to transform fields to be easier for next group
// cal nsBlocksCovered
group module&source ,ns to sum typeBlocksCovered -> nsBlocksCovered) + push types back to ns
project to transform fields to be easier for next group
// cal coveredBlocks
group module&source to sum nsBlocksCovered  -> coveredBlocks
project to transform fields to match your mongoose docs

我的示例查询使用mongo shell语法并且看起来很有效,猜猜您使用的是集合名称“Coverage”

db.Coverage.aggregate([
    {"$unwind":("$namespaces")}
    ,{"$unwind":("$namespaces.types")}
    ,{"$unwind":("$namespaces.types.functions")}
    ,{"$group": {
        _id: {module:"$module", source:"$source", nsName: "$namespaces.name", typeName : "$namespaces.types.name"}
        , typeBlocksCovered : { $sum : "$namespaces.types.functions.blocksCovered"}
        , functions:{ "$push": "$namespaces.types.functions"}}} 
    ,{"$project" :{module:"$_id.module", source:"$_id.source"
                    ,namespaces:{ 
                        name:"$_id.nsName"
                        ,types : { name: "$_id.typeName",typeBlocksCovered : "$typeBlocksCovered" ,functions: "$functions"}
                    }
                    ,_id:0}}  
    ,{"$group": {
        _id: {module:"$module", source:"$source", nsName: "$namespaces.name"}
        , nsBlocksCovered : { $sum : "$namespaces.types.typeBlocksCovered"}
        , types:{ "$push": "$namespaces.types"}}}
    ,{"$project" :{module:"$_id.module", source:"$_id.source"
                    ,namespaces:{ 
                        name:"$_id.nsName"
                        ,nsBlocksCovered:"$nsBlocksCovered"
                        ,types : "$types"
                    }
                    ,_id:0}}
    ,{"$group": {
        _id: {module:"$module", source:"$source"}
        , coveredBlocks : { $sum : "$namespaces.nsBlocksCovered"}
        , namespaces:{ "$push": "$namespaces"}}}
    ,{"$project" :{module:"$_id.module", source:"$_id.source", coveredBlocks : "$coveredBlocks", namespaces: "$namespaces",_id:0}}       
])