Вернуть уникальные значения по ключу в CouchDB - PullRequest
8 голосов
/ 28 марта 2011

Есть ли способ сделать следующее в CouchDB?Способ вернуть уникальные, уникальные значения по данному ключу?

SELECT DISTINCT field FROM table WHERE key="key1"

'key1' => 'somevalue'
'key1' => 'somevalue'
'key2' => 'anotherval'
'key2' => 'andanother'
'key2' => 'andanother'

Например:

http://localhost:5984/database/_design/designdoc/_view/distinctview?key="key1" вернет ['somevalue']

http://localhost:5984/database/_design/designdoc/_view/distinctview?key="key2" вернёт ['anotherval', 'andanother']

Ответы [ 2 ]

9 голосов
/ 29 марта 2011

Как предлагается в окончательном руководстве CouchDB , вы должны поместить значения, которые вы хотите быть уникальными, в ключ, а затем запросить функцию уменьшения с помощью group=true.

Например,учитывая, что keyfield - это поле с «key1» и «key2», а valuefield - это поле со значениями, ваша функция карты может быть:

function(doc) {
  // filter to get only the interesting documents: change as needed
  if (doc.keyfield && doc.valuefield) {
    /*
     * This is the important stuff:
     * 
     *  - by putting both, the key and the value, in the emitted key,
     *    you can filter out duplicates
     *    (simply group the results on the full key);
     * 
     *  - as a bonus, by emitting 1 as the value, you get the number
     *    of duplicates by using the `_sum` reduce function.
     */
    emit([doc.keyfield, doc.valuefield], 1);
  }
}

, а ваша функция уменьшения может быть:

_sum

Затем запрос с помощью group=true&startkey=["key2"]&endkey=["key2",{}] дает:

{"rows":[
{"key":["key2","anotherval"],"value":1},
{"key":["key2","andanother"],"value":2}
]}
3 голосов
/ 28 марта 2011

Исходя из того, что я вижу здесь, (я изменю свой ответ, если необходимо) key1 и key2 выглядят как независимые поля, поэтому вам потребуется 2 отдельных представления.

Я создал 5 простых документов в моей тестовой базе данных:

// I've left out fields like _id and _rev for the sake of simplicity
{ "key1": "somevalue" }
{ "key1": "somevalue" }
{ "key2": "anotherval" }
{ "key2": "andanother" }
{ "key2": "andanother" }

Вот 2 запроса на просмотр, которые вам понадобятся:

// view for key1
function(doc) {
  if (doc.key1) {
    emit("key1", doc.key1);
  }
}

// view for key2
function(doc) {
  if (doc.key2) {
    emit("key2", doc.key2);
  }
}

Оттуда ваша функция Reduce может возвращать все значения в массиве, просто делая это:

function (key, values) {
  return values;
}

Однако вы специально упомянули различных значений. Поскольку в JavaScript нет собственного метода unique() для массивов, и мы не можем использовать модули CommonJS в функциях представления, для этого нам придется добавить собственную логику. Я только что скопировал первую функцию array.unique(), которую я нашел в Google, вы можете написать свою собственную, которая наверняка лучше оптимизирована.

function (key, values, rereduce) {
  var o = {}, i, l = values.length, r = [];

  for (i = 0; i < l; i += 1) {
    o[values[i]] = values[i];
  }

  for (i in o) {
    r.push(o[i]);
  }

  return r;
}

Вы будете использовать одну и ту же функцию уменьшения в обоих представлениях. Когда вы запрашиваете любое из этих представлений, по умолчанию оно также выполняет уменьшение. (Вам нужно явно передать reduce=false, чтобы получить только результаты вашей map функции.

Вот наборы результатов, которые вы получите, используя вышеуказанные map/reduce запросы: (помните, что это 2 отдельных запроса)

{"rows":[
  {"key":"key1", "value": ["somevalue"]}
]}

{"rows":[
  {"key": "key2", "value": ["anotherval", "andanother"]}
]}
...