【问题标题】:Retrieving, operating and storing date back in datetime在日期时间中检索、操作和存储日期
【发布时间】:2014-01-18 01:14:45
【问题描述】:

注意:我在输出中只提供了一些文档以保持帖子小而直观

源集合:

{
        "_id" : {
                "SpId" : 840,
                "Scheduler_Id" : 1,
                "Channel_Id" : 2,
                "TweetId" : 15
        },
        "PostDate" : ISODate("2013-10-31T18:30:00Z")
}
{
        "_id" : {
                "SpId" : 840,
                "Scheduler_Id" : 1,
                "Channel_Id" : 2,
                "TweetId" : 16
        },
        "PostDate" : ISODate("2013-10-31T18:30:00Z")
}
{
        "_id" : {
                "SpId" : 840,
                "Scheduler_Id" : 1,
                "Channel_Id" : 2,
                "TweetId" : 17
        },
        "PostDate" : ISODate("2013-10-30T18:30:00Z")
}

第 1 步:按 PostDate 分组

查询:

db.Twitter_Processed.aggregate({$match : { "_id.SpId" : 840, "_id.Scheduler_Id" : 1 }},{$project:{SpId : "$_id.SpId",Scheduler_Id : "$_id.Scheduler_Id",day:{$dayOfMonth:'$PostDate'},month:{$month:'$PostDate'},year:{$year:'$PostDate'}, senti : "$Sentiment"}}, {$group : {_id : {SpId : "$SpId", Scheduler_Id : "$Scheduler_Id",day:'$day',month:'$month',year:'$year'}, sentiment : { $sum : "$senti"}}}, {$group : {_id : "$_id" , avgSentiment : {$avg : "$sentiment"}}})

输出:

{
        "result" : [
                {
                        "_id" : {
                                "SpId" : 840,
                                "Scheduler_Id" : 1,
                                "day" : 31,
                                "month" : 10,
                                "year" : 2013
                        },
                        "avgSentiment" : 2.2700000000000005
                },
                {
                        "_id" : {
                                "SpId" : 840,
                                "Scheduler_Id" : 1,
                                "day" : 30,
                                "month" : 10,
                                "year" : 2013
                        },
                        "avgSentiment" : 4.96
                }
}

第 2 步:尝试实现这一目标:

{
        "result" : [
                {
                        "_id" : {
                                "SpId" : 840,
                                "Scheduler_Id" : 1,
                 "Date" : ISODate("2013-10-31T18:30:00Z")
                        },
                        "avgSentiment" : 2.2700000000000005
                },
                {
                        "_id" : {
                                "SpId" : 840,
                                "Scheduler_Id" : 1,
                "Date" : ISODate("2013-10-31T18:30:00Z")
                        },
                        "avgSentiment" : 4.96
                }
}

尝试过的查询

db.Twitter_Processed.aggregate({$match : { "_id.SpId" : 840, "_id.Scheduler_Id" : 1 }},{$project:{SpId : "$_id.SpId",Scheduler_Id : "$_id.Scheduler_Id",day:{$dayOfMonth:'$PostDate'},month:{$month:'$PostDate'},year:{$year:'$PostDate'}, senti : "$Sentiment"}}, {$group : {_id : {SpId : "$SpId", Scheduler_Id : "$Scheduler_Id",day:'$day',month:'$month',year:'$year'}, sentiment : { $sum : "$senti"}}}, {$group : {_id : "$_id" , avgSentiment : {$avg : "$sentiment"}}}, {$project : {_id : {SpId : "$_id.SpId",Scheduler_Id : "$_id.Scheduler_Id", date : new Date("$_id.year","$_id.month","$_id.day")}, avgSentiment : "$avgSentiment"}})

输出(错误):

Error: Printing Stack Trace
    at printStackTrace (src/mongo/shell/utils.js:37:15)
    at DBCollection.aggregate (src/mongo/shell/collection.js:897:9)
    at (shell):1:22
Tue Dec 31 09:41:42.916 JavaScript execution failed: aggregate failed: {
        "errmsg" : "exception: disallowed field type Date in object expression (
at 'date')",
        "code" : 15992,
        "ok" : 0
} at src/mongo/shell/collection.js:L898

如何实现步骤 2?

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework document-database


    【解决方案1】:

    正如您所注意到的,聚合框架(在 MongoDB 2.4 中)具有要提取的运算符 日期的一部分,但不容易创建日期字段。

    Stupid date tricks with Aggregation Framework 上有一篇很棒的博文,它提供了一个创造性的解决方法:在您使用 $group 之前使用 $project 截断日期粒度:

    db.Twitter_Processed.aggregate(
    
        // Match (can take advantage of suitable index)
        { $match : {
            "_id.SpId" : 840,
            "_id.Scheduler_Id" : 1
        }},
    
        // Extract h/m/s/ms values from PostDate for rounding
        { $project: {
            SpId : "$_id.SpId",
            Scheduler_Id : "$_id.Scheduler_Id",
            PostDate : "$PostDate",
            h  : { "$hour"   : "$PostDate" },
            m  : { "$minute" : "$PostDate" },
            s  : { "$second" : "$PostDate" },
            ms : { "$millisecond" : "$PostDate" },
            senti : "$Sentiment"
        }},
    
        // Subtract the h/m/s/ms values to round the date off to yyyy-mm-dd
        { $project: {
            SpId : "$_id.SpId",
            Scheduler_Id : "$_id.Scheduler_Id",
    
            // PostDate will end up truncated to yyyy-mm-dd granularity
            PostDate: {
                "$subtract" : [
                    "$PostDate",
                    {
                        "$add" : [
                            "$ms",
                            { "$multiply" : [ "$s", 1000 ] },
                            { "$multiply" : [ "$m", 60, 1000 ] },
                            { "$multiply" : [ "$h", 60, 60, 1000 ]}
                        ]
                    }
                ]
            },
            senti: "$Sentiment"
        }},
    
        { $group : {
            _id : {
                SpId : "$SpId",
                Scheduler_Id : "$Scheduler_Id",
                PostDate: "$PostDate"
            },
            sentiment : { $sum : "$senti"}
        }},
    
        { $group : {
            _id : "$_id" ,
            avgSentiment : {$avg : "$sentiment"}
        }}
    )
    

    【讨论】:

    • 工作得很好:) 我只是有点不清楚舍入的减法;这在数据库级别到底做了什么 - 它是一个简单的 $PostDate 转换为字符串,然后截断/删除 h、s 等,还是它真的创建另一个日期对象并从 $PostDate 对象中减去它并给出一个新的截断日期对象?
    • 这会通过减去不需要的时间分量将聚合管道中的 $PostDate 截断为每日值。然后,您可以通过 $PostDate(它仍然是 Date 对象,但实际上是 yyyy-mm-dd)$group,而不是尝试使用单独的 yyyy/mm/dd 字段重新创建 Date。创建新日期的操作员在这里会有所帮助,因此可以在$group 中表示粒度,而无需这种解决方法。这很古怪,但我 认为 发生的情况是,在分组时可以将没有 ms 精度的日期强制转换为兼容类型。必须查看源代码才能确定。
    • 这是一个相关的功能请求,您可以在 Jira 中观看/投票:SERVER-11118: Add dateFormat (strftime) aggregation operator
    猜你喜欢
    • 1970-01-01
    • 2013-08-20
    • 2017-11-01
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    相关资源
    最近更新 更多