简体   繁体   中英

mongodb aggregation of multiple values

I am trying analytics with mongodb , but i am very new at it although i got it working for 1 query i don't think its efficient one , here is my example of my dataset

{
_id: ObjectId("54442882fa2e117a55f3458b"),
analytic_num: 185,
createdAt: ISODate("2014-10-19T21:09:22.167Z"),
updatedAt: ISODate("2014-10-19T21:09:22.167Z"),
rawBrowser: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:33.0) Gecko/20100101 Firefox/33.0",
gender: "male",
eventId: "accepted",
type: "member",
relationshipStatus: "Single",
ageRange: "18-25",
uid: "53f79ae6f158168161f04d27",
cid: "54370fa7498a776e1c065120",
education: ["high_school", "professional_degree"],
interestedIn: ["female"],
__v: 0
}

here is the query m trying

db.analytics.aggregate([{
$match: {
    createdAt: {
        $gte: new Date(2014, 9, 15),
        $lt: new Date(2014, 9, 28)
    }
}
}, {
$project: {
    _id: 0,
    minute: {
        $minute: "$createdAt"
    },
    hour: {
        $hour: "$createdAt"
    }
}
}, {
$group: {
    _id: {
        minute: "$minute",
        hour: "$hour"
    },
    hits: {
        $sum: 1
    }
}
}]);

here is the result i am getting

{ "_id" : { "minute" : 33, "hour" : 21 }, "hits" : 1 }
{ "_id" : { "minute" : 29, "hour" : 21 }, "hits" : 6 }
{ "_id" : { "minute" : 6, "hour" : 22 }, "hits" : 2 }
{ "_id" : { "minute" : 9, "hour" : 21 }, "hits" : 1 }

everything is fine but i only get hits for every minute of every hour , thats fine if i just want only hits

but i if need to find out hits by type or gender or ageRange i need to change $match query, thats not efficient to run this query for all the attributes by changing $matvh

How can i get all the hits for type,gender, angRange in one query i want result like this

{ "_id" : { "minute" : 33, "hour" : 21 }, "hits" : 30, "member" :2 "single": 12 ,"male" :12 }
{ "_id" : { "minute" : 34, "hour" : 21 }, "hits" : 50, "member" :22 "single": 12 ,"male" :12 }

Pls help

thanks

You are looking for the $cond operator. This allows you to evaluate a condition and then make a decision on whether this returns true|false to which value you want to return. In this case, whether you want to add an increment to a $sum operation or whether you don't:

db.analytics.aggregate([
    { "$match": {
        "createdAt": {
            "$gte": new Date(2014, 9, 15),
            "$lt": new Date(2014, 9, 28)
        }
    }}, 
    { "$group": {
        "_id": {
            "minute": { "$minute": "$createdAt" },
            "hour": { "$hour": "$createdAt" }
        },
        "hits": { "$sum": 1 },
        "member": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$type", "member" ] },
                    1,
                    0
                ]
            }
        },
        "single": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$relationshipStatus", "single" ] },
                    1,
                    0
                ]
            }
        },
        "male": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$gender", "male" ] },
                    1,
                    0
                ]
            }
        }
    }}
]);

So the $cond operator is basically a "ternary", or if..then..else construct, which evaluates a condition and returns a value based on how that condition was determined, true|false . You use it in this way to determine the value returned.

Be careful with date aggregation operators. Maybe what you want here is every minute of every hour, aggregated for all days within that range. But usually people just want the discrete time periods over each day, even by the minute.

Be careful what you ask for, you just might get it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM