如何在mongodb中嵌套总和

时间:2014-06-10 12:28:07

标签: mongodb aggregation-framework

我有这个计划:

[{
        name: 'John',
        plays: [{
                playNum: 1,
                song: {
                    length: 400,
                    param: 'a'
                }
            }, {
                playNum: 2,
                song: {
                    length: 350,
                    param: 'a'
                }
            }, {
                playNum: 3,
                song: {
                    length: 211,
                    param: 'a'
                }
            ]
        },
        {
            name: 'John',
            plays: [{
                    playNum: 2,
                    song: {
                        length: 400,
                        param: 'a'
                    }
                }, {
                    playNum: 3,
                    song: {
                        length: 350,
                        param: 'a'
                    }
                }, {
                    playNum: 4,
                    song: {
                        length: 211,
                        param: 'a'
                    }
                ]
            }
        ]

我想计算特定比赛的时间 即对于第2场比赛 - 我们在350中有一首歌曲,在400 = 750时有另一首歌曲。

我试图这样做:

aggregate(
        {$match : { "shows.showNum" : showNum } },
        {$unwind : "$shows"},
        {$group : {_id : "$shows.showNum", totalLength : { $sum : "$shows.song.length" }}})

但是通过这种方式,我得到了在该节目中播放的所有歌曲的总数。

任何人都可以帮忙吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

您的第一个$match仅匹配数组中包含该值的“文档”。要实际“过滤”数组内容,您需要在管道中$match之后另外$unwind

db.collection.aggregate([
    { "$match": { "plays.playNum" : playNum } },
    { "$unwind": "$plays"},
    { "$match": { "plays.playNum" : playNum } },
    { "$group": {
        "_id" : "$plays.playNum", 
        "totalLength": { "$sum" : "$plays.song.length" }
    }}
])

如果你有MongoDB 2.6或更高版本,你可以使用$map运算符和其他辅助运算符实际过滤数组:

db.collection.aggregate([
    { "$match": { "plays.playNum" : playNum } },
    { "$project": {
        "plays": {
             "$setDifference": [
                {
                    "$map": {
                        "input": "$plays",
                        "as": "el",
                        "in": {
                            "$cond": [
                                { "$eq": [ "$$el.playNum", playNum ] },
                                "$$el",
                                false
                            ]
                        }
                    }
                ],
                [false]
            ]
        }
    }},
    { "$unwind": "$plays" },
    { "$group": {
        "_id" : "$plays.playNum", 
        "totalLength": { "$sum" : "$plays.song.length" }
    }}
])

通过组合各个阶段的功能,使事情变得更快。它看起来更复杂,但实际上是处理最终结果的最快方式。

答案 1 :(得分:0)

db.collection.aggregate([
    {$unwind: '$plays'}, 
    {$match: {"plays.playNum" : 2} },
    {$group: {
        _id: null, 
        "suma": {$sum: "$song.length" }
    }}
])