【问题标题】:MongoDB, return recent document for each user_id in collectionMongoDB,为集合中的每个 user_id 返回最近的文档
【发布时间】:2011-07-06 02:28:20
【问题描述】:

寻找与 Postgres 的 Distinct On 类似的功能。

有一个文档集合 {user_id, current_status, date},其中状态只是文本,日期是日期。仍处于围绕 mongo 探索最佳方法的早期阶段。

mapreduce 会是这里最好的解决方案吗,map 发出所有,reduce 记录最新的,还是有一个内置的解决方案而不拉出 mr?

【问题讨论】:

    标签: mongodb mapreduce


    【解决方案1】:

    有一个distinct command,但我不确定这是否是您所需要的。 Distinct 是一种“查询”命令,如果有很多用户,您可能不希望实时汇总数据。

    Map-Reduce 可能是一种方法。

    Map Phase:您的key 只是一个ID。您的value 将类似于以下{current_status:'blah',date:1234}

    减少阶段:给定一组值,您将获取最新的值并仅返回它。

    为了使这项工作达到最佳状态,您可能需要查看 1.8.0 中的一项新功能。 "re-reduce" feature。将允许您仅处理新数据,而不是重新处理整个状态集合。

    另一种方法是构建一个“最近的”集合并将状态插入绑定到该集合。因此,当您为用户插入新状态时,您会更新他们的“最近”状态。

    根据此功能的重要性,您可以同时做这两件事。

    【讨论】:

    • 谢谢,我认为这两种方法都值得研究,尤其是重新减少。
    • 考虑到最新的收集方法,似乎这会给插入过程增加很多开销,我想避免这种情况,因为无论如何这是我使用 mongo 的原因的一部分。我需要使用为每个 ID 插入的 ID 来搜索/删除状态。虽然由于它的索引和较小的集合,这不应该很快,但 mongo 确实存在锁定整个集合以进行删除的“问题”,因此“似乎”这将是一个很大的权衡。
    • 您可以非常快地发送upsertupsert“如果存在则更新否则创建”。所以没有删除或没有额外的查询。在 JS 中,这看起来像以下 db.most_recent.update({_id:user_id},{status:"blah"},false,true),请检查您的语言驱动程序是否有“upsert”。
    • 是的,我记得我上次发表评论后不久就更新了。由于我有一个增长相当快的用户组,我认为最近的收藏是做到这一点的最佳方式,所以我正在朝着这个方向前进。感谢您的回答
    【解决方案2】:

    目前看来运行良好的解决方案。

    map = function () {emit(this.user.id, this.created_at);}
    
    //We call new date just in case somethings not being stored as a date and instead just a string, cause my date gathering/inserting function is kind of stupid atm
    
    reduce = function(key, values) { return new Date(Math.max.apply(Math, values.map(function(x){return new Date(x)})))}
    
    
    res = db.statuses.mapReduce(map,reduce);
    

    【讨论】:

      【解决方案3】:

      实现相同结果的另一种方法是使用 group 命令,这是一种 mr 快捷方式,可让您聚合特定键或一组键。 在您的情况下,它将如下所示:

      db.coll.group({ key : { user_id: true },
                      reduce : function(obj, prev) { 
                                 if (new Date(obj.date) < prev.date) { 
                                   prev.status = obj.status; 
                                   prev.date = obj.date; 
                                 }
                               },
                    initial : { status : "" }
      }) 
      

      但是,除非您的用户数量很少,否则我坚信更好的解决方案是,如前所述,保留一个单独的集合,其中仅包含每个用户的最新状态消息。

      【讨论】:

      • 感谢组的建议,但是组不能与分片一起使用,这是我要避免的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多