Лучший способ сделать один-ко-многим "ПРИСОЕДИНИТЬСЯ" в CouchDB - PullRequest
33 голосов
/ 13 июня 2010

Я ищу CouchDB, эквивалентный "объединениям SQL".

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

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

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

{ "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
    }
  }
}

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

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


РЕДАКТИРОВАТЬ: не пропустите комментарий Джейсона Смита к своему ответу, где он описывает, как это сделатькороче.

1 Ответ

51 голосов
/ 14 июня 2010

Спасибо! Это отличный пример для демонстрации нового CouchDB 0.11 Особенности !

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

Вот план:

  1. Во-первых, у вас есть ограничения уникальности в ваших 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, но добавляет сложности.

  2. Представление генерирует {"_id": content_id} данные, включенные [list_id, sort_number], для «объединения» списков с их содержимым.

    function(doc) {
      if(doc.type == 'list') {
        for (var i in doc.elements) {
          // Link to the el document's 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"}}
    ]}
    
  3. Чтобы получить содержимое 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. Следующий необязательно step просто переформатирует его в соответствии с тем, что вам нужно.

  4. Используйте функцию _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"]}
    
...