【问题标题】:Dynamic Frequency Map from MongoDB Keys来自 MongoDB 键的动态频率图
【发布时间】:2015-06-16 22:05:23
【问题描述】:

我正在通过 Meteor 使用 MiniMongo,我正在尝试根据一组动态查询创建频率表。

我有两个主要字段,localHourlocalDay。我预计会有很多重叠,我想确定重叠最多的地方。我目前的做法是这样的。

if(TempStats.findOne({
            localHour: hours,
            localDay: day
          })){//checks if there is already some entry on the same day/hour

            TempStats.update({//if so, we just increment frequency
              localHour: hours,
              localDay: day
            },{
              $inc: {freq: 1}
            })

          } else {//if nothing exists yet, we put in a new entry

            TempStats.insert({
              localHour: hours,
              localDay: day,
              freq: 1
            });

          }

基本上,每次我有要插入的新数据时,这段代码都会运行。目前它工作正常,因为在插入所有数据之后,我可以按频率排序以找出最常出现的时间和日期集(TempStats.find({}, {sort: {freq: -1}}).fetch())。

但是,我正在寻找一种按频率搜索任何键的方法。例如,搜索所有事情最常发生的,而不是日期和小时。以我目前的方式,我需要有多个数据库和不同的插入方法,这有点荒谬。是否有 Mongo(特别是 MiniMongo)解决方案可以根据键进行频率映射?

谢谢!

【问题讨论】:

    标签: javascript mongodb meteor minimongo


    【解决方案1】:

    看起来miniMongo实际上不支持聚合,这使得这种操作变得困难。一种解决方法是在每天结束时汇总自己并将该汇总记录插入到您的数据库中(没有小时字段或将其设置为 -1 之类的值)。相反,您也可以在每次插入时更新该记录。这将允许您对两者使用相同的集合,并且在其他数据库中相当常见。

    您还应该考虑@nickmilon 的第一个建议,因为使用带有 $inc 运算符的 upsert 语句会将您的示例减少到每个数据点的单个操作。

    【讨论】:

      【解决方案2】:
      1. 关于您的代码的一个小注释:作为 else 语句的部分并不是真正需要的,如果您将其与选项 upsert=true 结合使用,您的更新将完成完整的工作,它将插入一个新文档,$inc 将根据需要将频率字段设置为 1,请参阅:herehere
      2. 对于计算频率的替代方法:假设您将日期存储为日期时间对象,我建议使用聚合(我不确定他们是否在 minimongo 中添加了对聚合的支持)但有 solutions 然后聚合,您可以将日期时间运算符用作 $hour, $week, etc 用于过滤和 $count 以计算频率,而无需在数据库中保留计数。

      【讨论】:

        【解决方案3】:

        这基本上是一个简单的 map-reduce 问题。

        首先,不要将派生数据分成 2 个字段。这违反了数据库最佳实践。如果数据以这种方式提供给您,请使用它来创建Date 对象。我假设您有一堆正在订阅的集合,然后您将所有这些集合到这个临时本地集合中。这是 map-reduce 模式的映射。此时,由于您的查询未知,因此聚合是浪费 CPU(即使它是您的客户端)。首先映射,然后减少。您应该拥有的是一个充满日期时间的集合。如果你愿意,就叫它TempMapCollection。现在,使用forEach() 并传入您的reduce 函数(按天、按小时等)。

        您可以缩减为另一个本地集合,或缩减为一个 javascript 对象。我喜欢使用集合,但如果对象很复杂,你会在那里得到所有的 EJSON 错误。由于您的对象只不过是一个日期时间,所以让我们使用集合。

        所以你有类似的东西:

        TempMapCollection.find().forEach(function(doc) {
            var date = doc.dateTime.getDate();
            TempReduceCollection.upsert({timequery: hours}, {$inc: {freq: 1}});
        })
        

        现在查询您的 reduce 集合。这有一个额外的好处,即如果您想要执行 2 个唯一查询,则无需重新映射。

        【讨论】:

        • 感谢您的帮助!很好的答案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多