简体   繁体   中英

Mongodb find distinct array fields and count them

I have a collection documents looks like:

{
    "_id" : ObjectId("560ba1e86db58e34168b456a"),
    "object_id" : "1722224",
    "user" : {
        "id" : null,
        "cookie" : "sEnAl9DdPHyTdmxYU3E23g"
    },
    "createddate" : ISODate("2015-09-30T11:48:40.000+03:00"),
    "activity" : [ 
        {
            "name" : "Map click",
            "selector" : "#toMap",
            "event" : "click",
            "time" : ISODate("2015-09-30T12:30:59.000+03:00")
        },
        {
            "name" : "Show contacts (main block)",
            "selector" : "#jsn-showContacts",
            "event" : "click",
            "time" : ISODate("2015-09-30T11:48:47.687+03:00")
        },
        {
            "name" : "Show contacts (main block)",
            "selector" : "#jsn-showContacts",
            "event" : "click",
            "time" : ISODate("2015-09-30T15:34:12.000+03:00")
        }
    ]
}

I need to pass to mongodb range of dates and get a day-by-day result that contains: 1. Date 2. Set of selectors clicked that date and count of that clicks:

{
    "date" :  ISODate("2015-09-29T00:00:00.000+03:00"),
    "selectors" : [
        {"#toMap" : 100},
        {"#jsn-showContacts" : 200}
    ]
},   
{
    "date" :  ISODate("2015-09-30T00:00:00.000+03:00"),
    "selectors" : [
        {"#toMap" : 50},
        {"#jsn-showContacts" : 80},
        {"#toOrder" : 10}
    ]
}

The result should count click once for every document, for example if i have two #showContacts-Min clicks in one document:

"activity" : [ 
            {
                "name" : "Show contacts (main block)",
                "selector" : "#jsn-showContacts",
                "event" : "click",
                "time" : ISODate("2015-09-30T11:48:47.687+03:00")
            },
            {
                "name" : "Show contacts (main block)",
                "selector" : "#jsn-showContacts",
                "event" : "click",
                "time" : ISODate("2015-09-30T15:34:12.000+03:00")
            }
        ]

it have to be couned once.

Is it really possible to do on DB side as one query or should it be implemented on application side with multiple db queries?

It is well possible to get desired result using single query.I'm assuming your "selector" values are prior know so that it can be hard coded in MongoDB query.

Here I have created sample documents as per your schema :

> db.a.find().pretty()
{
    "_id" : ObjectId("560ba1e86db58e34168b456a"),
    "object_id" : "1722224",
    "user" : {
            "id" : null,
            "cookie" : "sEnAl9DdPHyTdmxYU3E23g"
    },
    "createddate" : ISODate("2015-09-30T08:48:40Z"),
    "activity" : [
            {
                    "name" : "Map click",
                    "selector" : "#toMap",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T09:30:59Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T08:48:47.687Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T12:34:12Z")
            }
    ]
}
{
    "_id" : ObjectId("560c19550e45be0a683ccd01"),
    "object_id" : "1722224",
    "user" : {
            "id" : null,
            "cookie" : "sEnAl9DdPHyTdmxYU3E23g"
    },
    "createddate" : ISODate("2015-10-30T08:48:40Z"),
    "activity" : [
            {
                    "name" : "Map click",
                    "selector" : "#toMap",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T09:30:59Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T08:48:47.687Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T12:34:12Z")
            }
    ]
}
{
    "_id" : ObjectId("560c19750e45be0a683ccd02"),
    "object_id" : "1722224",
    "user" : {
            "id" : null,
            "cookie" : "sEnAl9DdPHyTdmxYU3E23g"
    },
    "createddate" : ISODate("2015-10-30T08:48:40Z"),
    "activity" : [
            {
                    "name" : "Map click",
                    "selector" : "#toMap",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T09:30:59Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T08:48:47.687Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T12:34:12Z")
            }
    ]
}
{
    "_id" : ObjectId("560c19940e45be0a683ccd03"),
    "object_id" : "1722224",
    "user" : {
            "id" : null,
            "cookie" : "sEnAl9DdPHyTdmxYU3E23g"
    },
    "createddate" : ISODate("2016-01-30T08:48:40Z"),
    "activity" : [
            {
                    "name" : "Map click",
                    "selector" : "#toMap",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T09:30:59Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T08:48:47.687Z")
            },
            {
                    "name" : "Show contacts (main block)",
                    "selector" : "#jsn-showContacts",
                    "event" : "click",
                    "time" : ISODate("2015-09-30T12:34:12Z")
            }
    ]
}

Below query will give your result.Here Count is selected without considering duplicate values within a single document

   >db.a.aggregate([{"$match":
{createddate:{"$gt": ISODate("2014-10-30T11:48:40.000+03:00"),
         "$lt":ISODate("2016-10-30T11:48:40.000+03:00")}}},
{'$group':{"_id":{"date":"$createddate"},
       "#toMap":{"$sum":{"$cond":{"if":{"$anyElementTrue":{
                                      "$map":{"input":"$activity",
                                               "as":"act",
                                               "in":{"$eq":    ["$$act.selector","#toMap"]}}}},"then":1,"else":0}}},
        "#jsn-showContacts":{"$sum":{"$cond":{"if":{"$anyElementTrue":{
                                        "$map":{
                                        "input":"$activity",
                                        "as":"act",
                                        "in":{"$eq":["$$act.selector","#jsn-    showContacts"]}}}},"then":1,"else":0}}}}}])
//Result:
{ "_id" : { "date" : ISODate("2016-01-30T08:48:40Z") }, "#toMap" : 1, "#jsn-showContacts" : 1 }
{ "_id" : { "date" : ISODate("2015-10-30T08:48:40Z") }, "#toMap" : 2, "#jsn-showContacts" : 2 }
{ "_id" : { "date" : ISODate("2015-09-30T08:48:40Z") }, "#toMap" : 1, "#jsn-showContacts" : 1 }

Selectors are not in an array in Result,But I hope this will do.You can use $project as last pipelie stage to modify result schema

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