有没有一种很好的方法来模仿CouchDB中SELECT COUNT(DISTINCT字段)的行为?
想象一下,我们有以下文档,它记录了用户播放某首歌的时间:
{
song_id: "happy birthday",
user_id: "boris",
date_played: [2011, 11, 14, 00, 12, 55],
_id: ...
}
我想知道我们的用户“boris”所播放的不同歌曲的数量。如果我们的用户已经听过20次“生日快乐”,那么该歌曲仍然只能为整首歌曲数量贡献+1。
在MySQL中,我只是执行SELECT COUNT(DISTINCT song_id) FROM plays WHERE user_id = "boris"
,但在CouchDB中写这篇文章时我只是空白。
解决方法1:如果我更改了架构,而是将所有歌曲播放存储在单个用户文档中的“boris”中,那么我可以编写一个映射来仅发出不同的值。但是,如果我想在last.fm的范围内构建一些东西,我担心随着“boris”文档大小(播放次数)的持续增长,更新将开始需要很长时间。 (我最终可能会遇到最大文档大小)。
解决方法2:我还可以编写一个map函数来返回所有的不同记录,我的python脚本可以自己总结一下;但同样有成千上万首不同的歌曲,这也会变得很慢。
我错过了哪些其他选择?
答案 0 :(得分:3)
这个答案由Zachary Zolton在couchdb邮件列表中提供:
既然你已经有了一个可以给你鲍里斯50k独特的观点 歌曲,您可以使用_list函数返回行数。
这样的事情可以解决问题:
function() {
var count = 0;
while(getRow()) count++;
return JSON.stringify({count: count});
}
如果查询此列表函数,则具有相同的视图,键范围和
小组级别,它只会回复一些JSON,例如:{"count":"50612"}
您可以在此处阅读更多内容:
答案 1 :(得分:2)
假设我已正确解释你的问题;
图:
function(doc) {
emit([doc.user_id, doc.song_id], null);
}
减少
_count
查询:
?startkey=[<userid>]&endkey=[<userid>,{}]&group=true
示例输出:
http://127.0.0.1:5984/foo/_design/a/_view/b?group=true&
startkey=[%22foo%22]&endkey=[%22foo%22,{}]
{"rows":[
{"key":["foo","bar"],"value":2},
{"key":["foo","bazbar"],"value":1}
]}
答案 2 :(得分:0)
我一直在努力完成同样的事情(见http://mail-archives.apache.org/mod_mbox/couchdb-user/201410.mbox/browser)
当你只需要一个标量值时,获得所有这些输出是不对的。即使列表功能是一种没有获得完整结果流的解决方法,这种方法也很奇怪。
任何替代方案吗?
答案 3 :(得分:0)
在CouchDB的最新版本(> 2.2)中,可以使用_approx_count_distinct reduce函数。您的看法将是:
地图:
function(doc) {
emit([doc.user_id, doc.song_id], 1);
}
减少:
_approx_count_distinct
,用于获取用户“ boris”的song_ids计数的查询为:
/db/_design/_myddoc/_view/myview?group_level=1&key=["boris"]