年齢をどの時間単位で求めるかは言われませんでしたが、分単位で戻す方法を説明し、それを他の時間単位に変換する方法を理解できると信じています。元のドキュメントには次のようなスキーマがあると仮定します。
{ _id: xxx,
post_id: uniqueId,
comments: [ { ..., date: ISODate() }, ..., { ... , date: ISODate() } ],
...
}
集計は次のとおりです。
// first you want to define some fixed point in time that you are calculating age from.
// I'm going to use a moment just before "now"
var now = new Date()-1
// unwind the comments array so you can work with individual comments
var unwind = {$unwind:"$comments"};
// calculate a new comment_age value
var project = {$project: {
post_id:1,
comment_age: {
$divide:[
{$subtract:[now, "$comments.date"]},
60000
]
}
} };
// group back by post_id calculating average age of comments
var group = {$group: {
_id: "$post_id",
age: {$avg: "$comment_age"}
} };
// now do the aggregation:
db.coll.aggregate( unwind, project, group )
$max、$min、およびその他のグループ化関数を使用して、最も古いコメントの日付と最も新しいコメントの日付、またはコメントの最低年齢と最高年齢を見つけることができます。post_id でグループ化するか、定数でグループ化して、コレクション全体のこれらの計算を見つけることができます。
*編集*
例として「図書館の本」に含めたドキュメントを使用すると、これは、「comments.cal_date」がチェックされたときであると仮定して、現在「アウト」になっている各本について計算するパイプラインである可能性がありますすべてのコメントの最新の cal_date は、現在の「チェックアウト」を表します (古いものが返されています)。
db.coll.aggregate( [
{ $match : { status : "Out" } },
{ $unwind : "$comments" },
{ $group : { _id : "$_id",
cal_date : { $max : "$comments.cal_date" }
}
},
{ $project : { outDuration : { $divide : [
{ $subtract : [
ISODate("2013-07-15"),
"$cal_date"
]
},
24*60*60*1000
]
}
}
},
{ $group : { _id : 1,
avgOut : { $avg : "$outDuration" }
}
}
] )
ステップが行っていること:
- に基づいてドキュメントをフィルタリングして、現在のみ
status
の本について計算します。Out
$unwind
「コメント」配列を平坦化して、できるようにします
- とを使用
cal_date
して、最新のエントリを見つけます。 $group
$max
- この max cal_date (書籍がいつチェックアウトされたかを表す) を使用して、今日の日付からそれを減算し、結果を 1 日のミリ秒数で割って、この書籍が発行された日数を取得します
$group
すべての結果をまとめて、チェックアウトされたすべての書籍の平均日数を見つけます。
*編集*
Rubyを知っていて、集計フレームワークコマンドを実行して日付の差/平均などを計算する方法を知る必要があると仮定していました. これは Ruby で "now" を使用して cal_date を比較する同じコードです (定数の日付値を使用して比較することもできます:
# get db collection from MongoClient into variable 'coll'
# see basic MongoDB Ruby driver tutorial for details
coll.aggregate([
{ "$match" => {"status"=>"Out"} },
{ "$unwind" => "$comments"},
{ "$group" => { "_id" => "$_id", "cal_date" => { "$max" => "$comments.cal_date" } } },
{ "$project"=> {
"outDuration" => {
"$divide" => [
{"$subtract" => [ Time.now, "$cal_date" ] },
24*60*60*1000
]
}
}
},
{ "$group" => {
"_id" => 1,
"avgOut" => {"$avg"=>"$outDuration"}
}
}
])
その他の例と説明については、 https://github.com/mongodb/mongo-ruby-driver/wiki/Aggregation-Framework-Examplesを参照してください。
フェーズで保持したい追加のフィールドがある場合は、次$group
のようにパイプライン ステップを変更して、さらにフィールドを追加できます。
{ $group : { _id : "$_id",
barcode : { $first : "$barcode" },
cal_date : { $max : "$comments.cal_date" }
}
}
オリジナルが必要ない場合は_id
、最初の行 (つまり_id: "$barcode"
) で "$_id" の代わりに "$barcode" を使用できますが、保存したいフィールドが複数ある可能性があるため、$first
トリックはそれらの数だけで機能します保持したい。