Лучший способ сделать один-ко-многим "JOIN" в CouchDB

Я ищу эквивалент CouchDB для "SQL-соединений".

В моем примере есть документы CouchDB, которые являются элементами списка:

{ "type" : "el", "id" : "1", "content" : "first" } 
{ "type" : "el", "id" : "2", "content" : "second" } 
{ "type" : "el", "id" : "3", "content" : "third" } 

Существует один документ, который определяет список:

{ "type" : "list", "elements" : ["2","1"] , "id" : "abc123" }

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

Результат может быть:

{ "content" : ["second", "first"] }

В этом случае порядок элементов уже как и должен быть. Другой возможный результат:

{ "content" : [{"content" : "first", "order" : 2},{"content" : "second", "order" : 1}] }

Я начал писать функцию карты:

map = function (doc) {
  if (doc.type === 'el') {
    emit(doc.id, {"content" : doc.content}); //emit the id and the content
    exit;
  }
  if (doc.type === 'list') {
    for ( var i=0, l=doc.elements.length; i<l; ++i ){
      emit(doc.elements[i], { "order" : i }); //emit the id and the order
    }
  }
}

Это насколько я могу получить. Можете ли вы исправить мои ошибки и написать функцию сокращения? Помните, что третий документ не должен быть частью результата.

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


EDIT: Не пропустите комментарий Джейсона Смита к его ответу, где он описывает, как сделать это короче.

Ответ 1

Спасибо! Это отличный пример, чтобы показать CouchDB 0.11 new особенности!

Вы должны использовать функцию связанных с выборкой данных для ссылок на документы в представлении. Дополнительно, для более удобного JSON используйте функцию _list для очистите результаты. Подробнее см. Couchio writeup на странице "JOIN" .

Вот план:

  • Во-первых, у вас есть уникальность в ваших документах el. Если два они имеют id = 2, что проблема. Необходимо использовать вместо поля _id, если id. CouchDB гарантирует уникальность, но также, для остальной части этого плана требуется _id, чтобы получить документы по идентификатору.

    { "type" : "el", "_id" : "1", "content" : "first" } 
    { "type" : "el", "_id" : "2", "content" : "second" } 
    { "type" : "el", "_id" : "3", "content" : "third" } 
    

    Если сменить документы на использование _id абсолютно невозможно, вы можете создайте простой вид emit(doc.id, doc), а затем снова вставьте его в временная база данных. Это преобразует id в _id, но добавляет некоторую сложность.

  • В представлении выбраны данные {"_id": content_id} [list_id, sort_number], чтобы "скопировать" списки с их содержимым.

    function(doc) {
      if(doc.type == 'list') {
        for (var i in doc.elements) {
          // Link to the el document id.
          var id = doc.elements[i];
          emit([doc.id, i], {'_id': id});
        }
      }
    }
    

    Теперь есть простой список документов el в правильном порядке. Ты можешь используйте startkey и endkey, если вы хотите увидеть только определенный список.

    curl localhost:5984/x/_design/myapp/_view/els
    {"total_rows":2,"offset":0,"rows":[
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"}},
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"}}
    ]}
    
  • Чтобы получить контент el, введите запрос include_docs=true. Через магию _id будут загружены документы el.

    curl localhost:5984/x/_design/myapp/_view/els?include_docs=true
    {"total_rows":2,"offset":0,"rows":[
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"},"doc":{"_id":"2","_rev":"1-4530dc6946d78f1e97f56568de5a85d9","type":"el","content":"second"}},
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"},"doc":{"_id":"1","_rev":"1-852badd683f22ad4705ed9fcdea5b814","type":"el","content":"first"}}
    ]}
    

    Обратите внимание, что это уже вся необходимая информация. Если ваш клиент гибкий, вы можете анализировать информацию из этого JSON. Следующий дополнительный шаг просто переформатирует его в соответствии с тем, что вам нужно.

  • Используйте функцию _list, которая просто переформатирует вывод представления. Люди используют их для вывода XML или HTML, но мы сделаем JSON более удобен.

    function(head, req) {
      var headers = {'Content-Type': 'application/json'};
      var result;
      if(req.query.include_docs != 'true') {
        start({'code': 400, headers: headers});
        result = {'error': 'I require include_docs=true'};
      } else {
        start({'headers': headers});
        result = {'content': []};
        while(row = getRow()) {
          result.content.push(row.doc.content);
        }
      }
      send(JSON.stringify(result));
    }
    

    Соответствие результатов. Конечно, для производства вам понадобятся startkey и endkey, чтобы указать нужный вам список.

    curl -g 'localhost:5984/x/_design/myapp/_list/pretty/els?include_docs=true&startkey=["abc123",""]&endkey=["abc123",{}]'
    {"content":["second","first"]}