MongoDB,返回集合中每个 user_id 最近的文档

5

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

有一个文档集合{user_id, current_status, date},其中状态只是文本,日期是一个日期。我还处于掌握mongo和了解最佳处理方式的早期阶段。

是否可以使用mapreduce作为最佳解决方案,map发出所有内容,reduce保留最新记录,或者有没有内置的解决方案而不需要使用mr?

3个回答

0

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

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);

0

实现相同结果的另一种方法是使用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 : "" }
}) 

然而,除非您只有相当少量的固定用户,否则我强烈认为更好的解决方案是,如先前建议的那样,保留一个单独的集合,仅包含每个用户的最新状态消息。


1
谢谢您提供的建议,但是由于无法在分片中使用group,我将避免使用该解决方案。 - Peck

0

有一个distinct命令,但我不确定这是否是您需要的。Distinct是一种“查询”命令,对于许多用户,您可能希望将数据汇总而不是实时处理。

Map-Reduce可能是解决此问题的一种方法。

映射阶段:您的key只需是一个ID。您的value将是以下内容之一:{current_status:'blah',date:1234}

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

为了使其最优化,您可能需要查看1.8.0中的新功能。"re-reduce" feature。将允许您仅处理新数据,而不是重新处理整个状态集合。

另一种方法是构建一个“最近”集合,并将状态插入与该集合相关联。因此,当您为用户插入新状态时,您会更新其“最近”的状态。
根据此功能的重要性,您可能可以同时执行这两个操作。

谢谢,我认为这两种方法都值得研究,特别是重新规约。 - Peck
考虑到最近的集合方法,似乎会给插入过程增加很多开销,这是我选择mongoDB的原因之一,所以我希望避免这种情况。我需要搜索/删除与我要插入的ID状态相同的每个ID。尽管它已经进行了索引,并且是一个较小的集合,但这不应该是快速的,MongoDB有“问题”,即锁定整个集合进行删除。因此,“似乎”这将是一个巨大的权衡。 - Peck
您可以执行一个非常快速的upsert操作。upsert是“如果存在则更新,否则创建”的意思。因此,没有删除或额外的查询。在JS中,它看起来像以下代码:db.most_recent.update({_id:user_id},{status:"blah"},false,true),请检查您的语言驱动程序是否支持“upsert”。 - Gates VP
是的,我在上一条评论后不久就记起了upsert。由于我的用户组正在迅速增长,我认为最近的集合是这样做的最佳方式,所以我正在朝着这个方向前进。 感谢您的回答。 - Peck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接