【问题标题】:Mongodb find distinct array fields and count themMongodb找到不同的数组字段并计算它们
【发布时间】:2015-09-30 14:10:12
【问题描述】:

我有一个集合文件看起来像:

{
    "_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")
        }
    ]
}

我需要将日期范围传递给 mongodb 并获得包含以下内容的每日结果: 1. 日期 2. 一组选择器点击该日期和点击次数:

{
    "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}
    ]
}

结果应该为每个文档计算一次点击,例如,如果我在一个文档中有两次 #showContacts-Min 点击:

"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")
            }
        ]

必须计算一次。

真的可以在 DB 端作为一个查询执行,还是应该在应用程序端通过多个 db 查询实现?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    使用单个查询很可能获得所需的结果。我假设您的“选择器”值是事先知道的,因此可以在 MongoDB 查询中进行硬编码。

    在这里,我根据您的架构创建了示例文档:

    > 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")
                }
        ]
    }
    

    下面的查询将给出您的结果。此处选择 Count 时不考虑单个文档中的重复值

       >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 }
    

    选择器不在结果中的数组中,但我希望这样做。您可以使用 $project 作为最后一个管道阶段来修改结果架构

    【讨论】:

    • 感谢您的回答,但关键是我不想将数据库逻辑移动到应用程序级别。选择器集不是固定的,它会随时间变化。当然,我可以尝试首先在我的应用程序中获取一组选择器,然后进行第二次查询,但如果可以在 DB 端对所有逻辑进行编程,我更愿意这样做。
    • 我明白你的意思,但是目前无法在 MongoDB 聚合查询中生成动态键名。最佳实用方法是尽可能将数据密集型工作卸载到 MongoDB。其余逻辑位置在应用程序中。我不认为您可以将所有逻辑编程到 DB。实际上 MongoDB 不建议这样做。
    • 谢谢。我将查询分成两部分。第一部分获取可用选择器的不同列表,然后应用程序使用您的答案中列出的方式基于该列表生成第二个查询。
    猜你喜欢
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 2013-09-19
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    相关资源
    最近更新 更多