如何将数字1格式化为字符串"01"进行聚合?

Mar*_*ian 6 mongodb mongodb-query aggregation-framework

我正在尝试根据我的文档中的日期字段以"YYYYMMDD"的形式创建聚合键.然而,使用$month$dayOfMonth运算符,我只返回数字,没有将它们格式化为前导零的方法(此外,我无法连接数字).

由于后者的阻塞性,我更喜欢聚合Map/Reduce.有任何想法吗?

Nei*_*unn 10

您基本上使用$concat运算符来加入具有一些条件的字符串,以及$substr处理转换:

"day": { 
    "$concat": [
        { "$substr": [ { "$year": "$date" }, 0, 4  ] },
        { "$cond": [
            { "$lte": [ { "$month": "$date" }, 9 ] },
            { "$concat": [
                "0", { "$substr": [ { "$month": "$date" }, 0, 2 ] }
            ]},
            { "$substr": [ { "$month": "$date" }, 0, 2 ] }
        ]},
        { "$cond": [
            { "$lte": [ { "$dayOfMonth": "$date" }, 9 ] },
            { "$concat": [
                "0", { "$substr": [ { "$dayOfMonth": "$date" }, 0, 2 ] }
            ]},
            { "$substr": [ { "$dayOfMonth": "$date" }, 0, 2 ] }
        ]}
    ]
}
Run Code Online (Sandbox Code Playgroud)

如果您按"日"汇总,另一种方法是使用带有日期数学的"纪元"值:

"day": {
    "$subtract": [
        { "$subtract": [ "$date", new Date("1970-01-01") ] },
        { "$mod": [
            { "$subtract": [ "$date", new Date("1970-01-01") ] },
            1000 * 60 * 60 * 24
        ]}
    ]
}
Run Code Online (Sandbox Code Playgroud)

对两个日期对象的任何日期数学运算都会导致epoch毫秒作为差异.因此,使用纪元日期作为日期对象进行转换.结果值是时间戳值的"日期",可以在处理结果时反馈以创建日期对象.

可以说你可以使用$year$dayOfYear结果在后期处理中做同样的事情,因为那些也足以在客户端处理中重新构成日期对象


Tho*_*4no 10

虽然尼尔的答案确实有效,但我觉得这样做并不令人满意; 它难以阅读,难以维护和缓慢.假设您从日期获得了价值(如OP中所述); 如果你使用mongo 3.0或更高版本,使用$ dateToString是最好的方法,但如果你坚持使用早期版本(比如我),我认为你最好只是从你想要的字符串中读取你想要的部分字符串.日期字段(因为这些是零填充):

formattedTime: {
    $concat: [
        { $substr: ["$timestamp", 0, 4] },
        { $substr: ["$timestamp", 5, 2] },
        { $substr: ["$timestamp", 8, 2] }
    ]
}
Run Code Online (Sandbox Code Playgroud)

这在我刚刚想要得到的情况下效果特别好<hours>:<minutes>(使用@ Neil的解决方案是正确的痛苦,因为我想零填充两个数字),但这种方式变得简单:formattedTime: { $substr: [ "$timestamp", 11, 5 ] }

当然,我建议用一些命名常量替换幻数以提高可读性.