Как написать запрос SELECT COUNT (поле DISTINCT) в CouchDB? - PullRequest
4 голосов
/ 15 ноября 2011

Есть ли хороший способ имитировать поведение SELECT COUNT (поле DISTINCT) в CouchDB?

Представьте, что у нас есть следующий документ, в котором записано время, когда пользователь играл определенную песню:

{
  song_id: "happy birthday",
  user_id: "boris",
  date_played: [2011, 11, 14, 00, 12, 55],
  _id: ...
}

Я бы хотел знать количество отдельных песен, когда-либо сыгранных нашим пользователем "boris" . Если наш пользователь прослушал «Happy Birthday» 20 раз, эта песня все равно должна внести всего +1 в общее количество песен.

В MySQL я просто выполнил бы SELECT COUNT(DISTINCT song_id) FROM plays WHERE user_id = "boris", но я рисую пробел, когда дело доходит до написания этого в CouchDB.

Work-Around 1: Если бы я изменил свою схему и вместо этого сохранил все пьесы в одном пользовательском документе для «boris», я мог бы тогда написать карту для выдачи только отдельных значений. Однако, если бы я захотел создать что-то в масштабе last.fm, я боюсь, что обновления начнут занимать очень много времени, так как размер документа «boris» (количество воспроизведений) продолжал расти. (Также может быть максимальный размер документа, который я в итоге получу).

Work-Around 2: Я также мог бы написать функцию карты, которая возвращает все отдельных записей, которые мой скрипт на Python мог бы суммировать сам; но опять же с сотнями тысяч разных песен это тоже станет очень медленным.

Какие еще опции мне не хватает?

Ответы [ 4 ]

3 голосов
/ 16 ноября 2011

Этот ответ предоставил Захари Золтон в списке рассылки 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"}

Вы можете прочитать больше здесь:

2 голосов
/ 15 ноября 2011

Если я правильно истолковал ваш вопрос;

карта:

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}
]}
0 голосов
/ 12 декабря 2018

В последних версиях CouchDB (> 2.2) вы можете использовать функцию _approx_count_distinct Reduce.Ваше представление будет:

map:

function(doc) {
    emit([doc.user_id, doc.song_id], 1);
}

Reduce:

_approx_count_distinct

, и запрос для получения количества song_ids для пользователя "boris" будет:

/db/_design/_myddoc/_view/myview?group_level=1&key=["boris"]
0 голосов
/ 16 октября 2014

Я боролся с точно таким же (см. http://mail -archives.apache.org / mod_mbox / couchdb-user / 201410.mbox / browser )

Просто нехорошо получать все эти выходные данные, когда вам просто нужно скалярное значение. Несмотря на то, что функция списка - это обходной путь для получения полного потока результатов, этот подход кажется очень странным.

Есть ли альтернативы для этого?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...