如何在CouchDB中编写SELECT COUNT(DISTINCT字段)查询?

时间:2011-11-15 07:15:14

标签: couchdb

有没有一种很好的方法来模仿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脚本可以自己总结一下;但同样有成千上万首不同的歌曲,这也会变得很慢。

我错过了哪些其他选择?

4 个答案:

答案 0 :(得分:3)

这个答案由Zachary Zolton在couchdb邮件列表中提供:

http://mail-archives.apache.org/mod_mbox/couchdb-user/201111.mbox/%3CCAGnHtbJ-1-YeLWMLivKzWub98HZY7%2BesnPOHU4pEYgWAsxaszA%40mail.gmail.com%3E

既然你已经有了一个可以给你鲍里斯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"]