MongoDBにDocumentというコレクションがあります。このコレクションのドキュメントには、CreationDateと呼ばれるフィールドがISO日付タイプに格納されています。私の仕事は、1日に作成されたドキュメントの数を数え、その数で非同期に並べ替えることです。出力形式は[{_id: 'yyyy-MM-dd'、cnt:x}]である必要があります。以下のように集計フレームワークを使用してみました。
db.Document.aggregate(
, {$project: {_id:1, Year:{$year:'$CreationDate'}, Month:{$month:'$CreationDate'}, Date:{$dayOfMonth:'$CreationDate'}}}
, {$group: {_id:{$concat:['$Year', '-', '$Month', '-', '$Date']}, cnt:{$sum:1}}}
, {$sort:{'cnt':-1}}
);
コードは私に以下のようなエラーを与えます:
$concat only supports strings, not NumberInt32
これは、$ year、$ month、および$ dayOfMonthがすべて数値を返すためです。 _idフィールドをオブジェクトとして作成し、アプリケーションレベルで目的の形式に再フォーマットすることができます。
しかし、技術的な観点から、2つの質問があります。
MongoDBシェルで数値を文字列に変換する方法は?この場合、$ yearの出力は文字列に変換され、$ concatで使用できます。
ISODate出力をさまざまな日付形式にフォーマットするより良い方法はありますか?多くの場合、ISODateの特定の部分(たとえば、日付コンポーネントや時間部分)のみが必要です。これを達成するためのMongoDb組み込みオペレーターはありますか?
アドバイスを事前にありがとう。
$concat
を使用してこれを行うことができますが、最初に $substr
、2桁の場合も処理します。
db.Document.aggregate([
{ "$group": {
"_id":{
"$concat": [
{ "$substr": [ { "$year": "$CreationDate" }, 0, 4 ] },
"-",
{ "$cond": [
{ "$gt": [ { "$month": "$CreationDate" }, 9 ] },
{ "$substr": [ { "$month": "$CreationDate" }, 0, 2 ] },
{ "$concat": [
"0",
{ "$substr": [ { "$month": "$CreationDate" }, 0, 1 ] },
]},
]},
"-",
{ "$cond": [
{ "$gt": [ { "$dayOfMonth": "$CreationDate" }, 9 ] },
{ "$substr": [ { "$dayOfMonth": "$CreationDate" }, 0, 2 ] },
{ "$concat": [
"0",
{ "$substr": [ { "$dayOfMonth": "$CreationDate" }, 0, 1 ] },
]}
]}
]
},
{ "cnt": { "$sum": 1 } }
}}
{ "$sort":{ "cnt" :-1 }}
]);
おそらく日付の計算を代わりに使用する方が良いかもしれません。これはエポックのタイムスタンプ値を返しますが、後処理で日付オブジェクトを操作するのは簡単です:
db.Document.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$CreationDate", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$CreationDate", new Date("1970-01-01") ] },
1000 * 60 * 60 * 24
]}
]
},
"cnt": { "$sum": 1 }
}},
{ "$sort": { "cnt": -1 } }
])
ISODateをさまざまな日付形式に変換するもう1つの簡単な方法は、 $ dateToString集計演算子 を使用することです。
db.collection.aggregate([
{ $group: {
_id: { $dateToString: { format: "%Y-%m-%d %H:%M", date: "$CreationDate" } },
count: { $sum: 1 }
}},
{ $sort : { count: -1 }}
])
私のように、2017年にこの質問に出くわした貧しい魂がいる場合:Mongo 3.0以降、 dateToString 演算子が利用可能になりました
つまり、適切なDate()があれば、簡単に実行できるはずです。
db.Document.aggregate(
, {$project: {_id:1, CreationDate:1}
, {$group: {
_id : { $dateToString: { format: "%Y-%m-$d", date: "$CreationDate" } },
cnt:{$sum:1}}}
, {$sort:{'cnt':-1}}
);
日付以外のフィールドに日付が格納されている場合(うれしい!)、プロジェクトステップで新しいDate()オブジェクトを作成できます。私の場合、日付はミリ秒(整数)の数として格納され、ミリ秒数を0-Dateに追加します。
db.Document.aggregate(
, {$project: {
_id:1,
CreationDate: {"$add": [ new Date(0), "$CreatedOn" ]}
}
, {$group: {
_id : { $dateToString: { format: "%Y-%m-$d", date: "$CreationDate" } },
cnt:{$sum:1}}}
, {$sort:{'cnt':-1}}
);
ニールの答えはその権利ですが、少しバグがあります。条件文(月と日の数の先頭に0を付ける必要があるかどうかを確認する)は$gt
ではなく$lte
です。
$lte
を使用すると、1桁の月と日のみに0が付加されます。
例:2014-10 - 3、2014 - 8 - 3。
日付形式を「xxxx-xx-xx」に変換するには
db.getCollection('analytics').aggregate([
{$project: {
day: {$dayOfMonth: "$createdAt"},
month: {$month: "$createdAt"},
year: {$year: "$createdAt"},
}
},
{$project: {
day: {$concat:["0", {$substr:["$day",0, 2]}]},
month: {$concat:["0", {$substr:["$month",0, 2]}]},
year: {$substr:["$year",0, 4]},
}
},
{$project: {date: {$concat: [{$substr:["$year",0, 4]},"-", {$substr:["$month",0, 2]},"-", {$substr:["$day",0, 2]}]}}},
]);