3

私はmongodbを使用しており、コメントを埋め込みドキュメントとして追加するモデルを持っています。

エントリのコメントの平均年齢を取得するにはどうすればよいですか? (相対的な例、私の分野は少し異なります)

そのため、1 つのエントリに多くのコメントを付けることができ、コメントの平均年齢、つまり平均年齢を調べる必要があります:cal_date:cal_date追加のメトリックは、すべてのエントリ/コメントまたはエントリごとの最大値などを収集するのに最適です...

これは理にかなっていますか?詳細が必要ですか?解決策を得る義務があることを嬉しく思います。しばらくの間、日付の計算に混乱していました。

これを考えるもう 1 つの方法は、図書館の本のモデルを使用することです。多くの本があり、各本には多くのチェックアウト/インがあります。各本がチェックアウトされる平均時間と、すべての本がチェックアウトされる平均時間を見つける必要があります。繰り返しますが、指標だけですが、これらがすべて日付であるという事実は紛らわしいです。

{
  _id: ObjectId("51b0d94c3f72fb89c9000014"),
  barcode: "H-131887",
  comments: [
    {
      _id: ObjectId("51b0d94c3f72fb89c9000015"),
      cal_date: ISODate("2013-07-03T16:04:57.893Z"),
      cal_date_due: ISODate("2013-07-03T16:04:57.894Z")
    },
    {
      _id: ObjectId("51b0e6053f72fbb27900001b"),
      cal_date: ISODate("2012-07-03T19:39:43.074Z"),
      cal_date_due: ISODate("2013-07-03T19:39:43.076Z"),
      updated_at: ISODate("2013-06-06T19:41:57.770Z"),
      created_at: ISODate("2013-06-06T19:41:57.770Z")
    }
  ],
  created_at: ISODate("2013-06-06T18:47:40.481Z"),
  creator_id: ObjectId("5170547c791e4b1a16000001"),
  description: "",
  maker: "MITUTOYO",
  model: "2046S",
  serial: "QEL228",
  status: "Out",
  updated_at: ISODate("2013-06-07T18:54:38.340Z")
}

もう1つ 、を使用して出力に追加のフィールドを含めるにはどうすればよい$pushですか? 私はこれを機能させることができますが、たとえばバーコードが配列に2回含まれています"barcode" => ["H-131887", "H-131887"]

4

1 に答える 1

1

年齢をどの時間単位で求めるかは言われませんでしたが、分単位で戻す方法を説明し、それを他の時間単位に変換する方法を理解できると信じています。元のドキュメントには次のようなスキーマがあると仮定します。

{ _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トリックはそれらの数だけで機能します保持したい。

于 2013-06-13T04:11:24.207 に答える