寻找类似于Postgres的Distinct On的功能。
有一个文档集合{user_id, current_status, date},其中状态只是文本,日期是一个日期。我还处于掌握mongo和了解最佳处理方式的早期阶段。
是否可以使用mapreduce作为最佳解决方案,map发出所有内容,reduce保留最新记录,或者有没有内置的解决方案而不需要使用mr?
目前看来运作良好的解决方案。
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);
实现相同结果的另一种方法是使用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 : "" }
})
然而,除非您只有相当少量的固定用户,否则我强烈认为更好的解决方案是,如先前建议的那样,保留一个单独的集合,仅包含每个用户的最新状态消息。
有一个distinct
命令,但我不确定这是否是您需要的。Distinct是一种“查询”命令,对于许多用户,您可能希望将数据汇总而不是实时处理。
Map-Reduce可能是解决此问题的一种方法。
映射阶段:您的key
只需是一个ID。您的value
将是以下内容之一:{current_status:'blah',date:1234}
。
减少阶段:给定一组值,您将获取最新的值并仅返回它。
为了使其最优化,您可能需要查看1.8.0中的新功能。"re-reduce" feature。将允许您仅处理新数据,而不是重新处理整个状态集合。
另一种方法是构建一个“最近”集合,并将状态插入与该集合相关联。因此,当您为用户插入新状态时,您会更新其“最近”的状态。upsert
操作。upsert
是“如果存在则更新,否则创建”的意思。因此,没有删除或额外的查询。在JS中,它看起来像以下代码:db.most_recent.update({_id:user_id},{status:"blah"},false,true)
,请检查您的语言驱动程序是否支持“upsert”。 - Gates VP