Как запросить PouchDB с помощью SQL-подобных операторов

Будучи относительно новым для PouchDB/CouchDB, я все еще пытаюсь понять, как правильно использовать карту/сокращение в разных случаях.

Предположим, что у меня есть такая структура документа:

{
  _id: 'record/1',
  labels: {
    // many-to-many relationship
    'label/1': true, // let's assume that this is 'Label A'
    'label/3': true, // 'Label C'
    'label/4': true // 'Label D'
  }
},
{
  _id: 'record/2',
  labels: {
    'label/1': true, // 'Label A'
    'label/2': true // 'Label B'
  }
}

Каковы правильные способы определения представления для функции db.query для поиска:

  1. записи с ярлыком A или с ярлыком B
  2. записи с ярлыком A и ярлыком B

person Kenny Ki    schedule 02.03.2015    source источник
comment
Посмотрите здесь. Ответ несколько предложений WHERE и OR должен вам помочь.   -  person Chris Snow    schedule 02.03.2015


Ответы (3)


В запросах mapreduce PouchDB/CouchDB нет операций OR, поэтому вам придется разбить их на два отдельных запроса.

Со временем такие операции будут поддерживаться в pouchdb-find, но на момент написания этой статьи $or еще не реализовано.

person nlawson    schedule 02.03.2015
comment
Плагин выглядит многообещающе. Хотя я не могу использовать его для этого случая, но я надеюсь использовать его в некоторых других случаях. - person Kenny Ki; 06.03.2015

Как бы я ни хотел использовать плагин pouchdb-find, я не мог найти способ добиться того, что мне было нужно. Вместо этого я использовал обходной путь:

Измените структуру документа, чтобы хранить идентификаторы меток в массиве.

{_id: 'record/1', name: 'Record 1', labels: ['label/1', 'label/2', 'label/3']},
// may not be sorted when being stored
{_id: 'record/2', name: 'Record 2', labels: ['label/1', 'label/5', 'label/7', 'label/3']},
{_id: 'record/3', name: 'Record 3', labels: ['label/2', 'label/3', 'label/4', 'label/5']}

Создать проектный документ

Он будет выдавать несколько сложных ключей для каждой записи, чтобы представить все возможные сопоставления меток в порядке возрастания. Функция map будет использовать рекурсивный процесс для генерации ключей:

{
  _id: '_design/records-with-labels',
  views: {
    'records-with-labels': {
      map: function(doc) {
        // important: sort them so that the required keys to be created are lesser
        var labelIds = doc.labels.sort();
        var lastIx = labelIds.length - 1;

        var emitKey = function emitKey(currentKey, currentIx) {
          console.log('emitting: ' + currentKey.join(',') + ' for ' + doc._id);
          emit(currentKey, null);

          var nextIx = currentIx + 1;

          for (var jumpIx = nextIx + 1; jumpIx <= lastIx; jumpIx++) {
            var jumpedLabelId = labelIds[jumpIx];
            var jumpingKey = currentKey.concat([jumpedLabelId]);

            console.log('emitting: ' + jumpingKey.join(',') + ' for ' + doc._id);
            emit(jumpingKey, null);
          }

          if (nextIx > lastIx) {
            return;
          }

          var nextLabelId = labelIds[nextIx];

          currentKey.push(nextLabelId);

          emitKey(currentKey, currentIx + 1);
        };

        labelIds.forEach(function(labelId, i) {
          emitKey([labelId], i);
        });

      }.toString()
    }
  }
}

Например, для документа record/1 будут сгенерированы следующие ключи:

emitting: label/1 for record/1
emitting: label/1,label/3 for record/1
emitting: label/1,label/2 for record/1
emitting: label/1,label/2,label/3 for record/1
emitting: label/2 for record/1
emitting: label/2,label/3 for record/1
emitting: label/3 for record/1

Запрос

Мне просто нужно убедиться, что метки запросов отсортированы в порядке возрастания.

Чтобы запросить записи с меткой/1 и меткой/3:

Db.query('records-with-labels', {
  key: ['label/1', 'label/3']
});

Чтобы запросить записи, которые содержат 'label/3' или 'label/3':

Db.query('records-with-labels', {
  keys: [['label/1'], ['label/3']]
});

Это даст нам повторяющиеся записи с обеими метками, но функция сокращения должна помочь их устранить.

Вывод

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

Если у вас есть лучшие предложения, прокомментируйте или отредактируйте ответ.

person Kenny Ki    schedule 06.03.2015

Это более старый пост. Однако можно использовать underscore.js, чтобы помочь с некоторыми запросами. Это может помочь извлечь нужные данные без необходимости совершать несколько обращений к базе данных (если вы этого не хотите).

person eDriven_Levar    schedule 16.03.2016