3

我正在使用 mongodb,并且有一个将注释添加为嵌入式文档的模型。

如何获取条目的平均评论年龄?(相对示例,我的字段略有不同)

所以我可以对一个条目有很多评论,我需要找出评论的平均年龄,或者平均:cal_date. 收集其他指标会很棒,例如:cal_date所有条目/评论或每个条目的最大值......

这有意义吗?需要更多细节?我很高兴有义务得到解决方案。一段时间以来,我一直对日期计算感到困惑。

另一种思考方式是使用图书馆图书模型:有很多书,每本书都有很多借出/借入。我需要找到每本书的平均检出时间所有书籍的平均检出时间。同样,只是指标,但这些都是日期的事实令人困惑。

{
  _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")
}

另一件事 我如何在我的输出中包含其他字段使用$push?我可以让它工作,但它包括,比如条形码,在一个数组中两次"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”是它被检查的时间out 并且所有评论的最新 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(表示该书的签出时间)将其从今天的日期中减去,然后将结果除以一天中的毫秒数,即可得出该书已售出的天数
  • $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")中使用“$barcode”而不是“$_id”,但由于您可能要保留多个字段,$firsttrick 可以使用尽可能多的字段你想保留。

于 2013-06-13T04:11:24.207 回答