比较2个计数聚合

时间:2018-06-19 05:56:12

标签: mongodb aggregation-framework

我在MongoDB中有一个类似于以下内容的集合:

{ "_id" : 1, "type" : "start", userid: "101", placementid: 1 }
{ "_id" : 2, "type" : "start", userid: "101", placementid: 2 }
{ "_id" : 3, "type" : "start", userid: "101", placementid: 3 }
{ "_id" : 4, "type" : "end", userid: "101", placementid: 1 }
{ "_id" : 5, "type" : "end", userid: "101", placementid: 2 }

我希望按userid然后placementid对结果进行分组,然后计算“开始”和“结束”的类型,但仅限于两个计数不同的情况。在这个特定的例子中,我想获得placementid: 3,因为在分组和计算时,这是计数不匹配的唯一情况。

我编写了一个获取2个计数和分组的查询,但是当计数不匹配时我无法进行过滤。这是我的问题:

db.getCollection('mycollection').aggregate([
    {
        $project: {
            userid: 1,
            placementid: 1,
            isStart: { 
                $cond: [ { $eq: ["$type", "start"] }, 1, 0] 
            },
            isEnd: { 
                $cond: [ { $eq: ["$type", "end"] }, 1, 0] 
            }
        }
    },
    {
        $group: {
            _id: { userid:"$userid", placementid:"$placementid" }, 
            countStart:{ $sum: "$isStart" },
            countEnd: { $sum: "$isEnd" }
        }
    },
    {
        $match: {
            countStart: {$ne: "$countEnd"}
        }
    }
])

我似乎错误地使用了匹配聚合,因为我看到countStartcountEnd相同的结果。

{ "_id" : {"userid" : "101", "placementid" : "1"}, "countStart" : 1.0, "countEnd" : 1.0 }
{ "_id" : {"userid" : "101", "placementid" : "2"}, "countStart" : 1.0, "countEnd" : 1.0 } 
{ "_id" : {"userid" : "101", "placementid" : "3"}, "countStart" : 1.0, "countEnd" : 0 } 

请问有人指出正确的方向吗?

2 个答案:

答案 0 :(得分:1)

要比较$match阶段内的两个字段,您需要MongoDB 3.6中提供的$expr

db.myCollection.aggregate([
    {
        $project: {
            userid: 1,
            placementid: 1,
            isStart: { 
                $cond: [ { $eq: ["$type", "start"] }, 1, 0] 
            },
            isEnd: { 
                $cond: [ { $eq: ["$type", "end"] }, 1, 0] 
            }
        }
    },
    {
        $group: {
            _id: { userid:"$userid", placementid:"$placementid" }, 
            countStart:{ $sum: "$isStart" },
            countEnd: { $sum: "$isEnd" }
        }
    },
    {
        $match: {
            $expr: { $ne: [ "$countStart", "$countEnd" ] }
        }
    }
])

如果您使用的是旧版MongoDB,则可以使用$redact

db.myCollection.aggregate([
    {
        $project: {
            userid: 1,
            placementid: 1,
            isStart: { 
                $cond: [ { $eq: ["$type", "start"] }, 1, 0] 
            },
            isEnd: { 
                $cond: [ { $eq: ["$type", "end"] }, 1, 0] 
            }
        }
    },
    {
        $group: {
            _id: { userid:"$userid", placementid:"$placementid" }, 
            countStart:{ $sum: "$isStart" },
            countEnd: { $sum: "$isEnd" }
        }
    },
    {
        $redact: {
            $cond: { if: { $ne: [ "$countStart", "$countEnd" ] }, then: "$$KEEP", else: "$$PRUNE" }
        }
    }
])

答案 1 :(得分:1)

你运行以下管道来获得这个 - 不需要使用$ expr或$ redact或任何特别的东西:

db.mycollection.aggregate({
    $group: {
        _id: {
            "userid": "$userid",
            "placementid": "$placementid"
        },
        "sum": {
            $sum: {
                $cond: {
                    if: { $eq: [ "$type", "start" ] },
                    then: 1, // +1 for start
                    else: -1 // -1 for anything else
                }
            }
        }
    }
}, {
    $match: {
        "sum": { $ne: 0 } // only return the non matching-up ones
    }
})