Представление CouchDB, создающее объекты JSON со встроенными массивами из двух отдельных документов - PullRequest
5 голосов
/ 28 июля 2010

Допустим, у меня есть два типа документов, хранящихся в моей базе данных CouchDB. Первый - с типом свойства, установленным на contact , а второй на phone . У документа типа контакта есть другое свойство, называемое именем. Тип телефона имеет номер свойства и contact_id, чтобы он мог ссылаться на контактное лицо. Это тривиальный сценарий, когда один контакт может иметь N телефонных номеров (я знаю, что они могут быть встроены в один документ контакта, но мне нужно продемонстрировать связь один ко многим с различными документами).

Пример необработанных данных: у Скотта 2 номера, а у Мэтта 1 номер:

{_id: "fc93f785e6bd8c44f14468828b001109", _rev: "1-fdc8d121351b0f5c6d7e288399c7a5b6", type: "phone", number: "123456", contact_id: "fc93f785e6bd8c44f14468828b00099f"}
{_id: "fc93f785e6bd8c44f14468828b000f6a", _rev: "1-b2dd90295693dc395019deec7cbf89c7", type: "phone", number: "465789", contact_id: "fc93f785e6bd8c44f14468828b00099f"}
{_id: "fc93f785e6bd8c44f14468828b00099f", _rev: "1-bd643a6b0e90c997a42d8c04c5c06af6", type: "contact", name: "Scott"}
{_id: "16309fcd03475b9a2924c61d690018e3", _rev: "1-723b7c999111b116c353a4fdab11ddc0", type: "contact", name: "Matt"}
{_id: "16309fcd03475b9a2924c61d69000aef", _rev: "3-67193f1bfa8ed21c68e3d35847e9060a", type: "phone", number: "789456", contact_id: "16309fcd03475b9a2924c61d690018e3"}

Функция карты:

function(doc) {
  if (doc.type == "contact") {
    emit([doc._id, 1], doc);
  } else if (doc.type == "phone") {
    emit([doc.contact_id, 0], doc);
  }
}

Функция уменьшения:

function(keys, values) {
  var output = {};

  for(var elem in values) {
    if(values[elem].type == "contact") {
      output = {
        "ID": values[elem]._id,
        "Name": values[elem].name,
        "Type": values[elem].type,
        "Phones": []
      };
    } else if (values[elem].type == "phone") {
      output.Phones.push({ 
        "Number": values[elem].number, 
        "Type": values[elem].type 
      });
    }
  }

  return output;
}

group_level установлен в 1 из-за ключей в функции Map. Теперь я могу получить свои контакты с включенными телефонами, например, так:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1

Или найдите какой-нибудь контакт с startkey и endkey следующим образом:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1&startkey=[%22fc93f785e6bd8c44f14468828b00099f%22]&endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,{}]

Результаты выглядят именно так, как я хочу - у контактов будут встроенные телефоны в соответствии с отношением один ко многим. И здесь возникает вопрос: это правильный способ использования функций MapReduce в CouchDB? Есть ли заметные проблемы с производительностью при использовании этого подхода?

Ответы [ 2 ]

7 голосов
/ 16 августа 2010

Вообще говоря, вы используете меньше дискового пространства, если вы не emit(...,doc).

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

Кроме того, я считаю, что в CouchDB заложено больше данных в функции сокращения, чем в ваших документах. Вы не делаете этого в этом случае, но вы следуете шаблону, который позже может привести к неприятностям. Это называется уменьшить по причине. : -)

Так что-то вроде этого больше похоже на CouchDB: function(doc) { if (doc.type == "contact") { emit([doc._id, 0], { "Name": doc.name, "Type": doc.type }); } else if (doc.type == "phone") { emit([doc.contact_id, 1], { "Number": doc.number, "Type": doc.type }); } }

Запросите его для определенного контакта, например так:

http://localhost:5984/testdb2/_design/testview/_view/tv1?
  startkey=[%22fc93f785e6bd8c44f14468828b00099f%22, 0]
  &endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,1]

Конечно, вы не получаете результаты в той же структуре JSON, что и раньше, но я считаю, что это лучше работает в CouchDB.

0 голосов
/ 29 июля 2010

Этот ответ полностью апокрифический и анекдотичный, но именно так я и работал с отношениями один-ко-многим в CouchDB. Если есть какие-либо проблемы с масштабированием, я их еще не видел. (Но я признаю, что не очень старался их найти.)

Несмотря на то, что в функции вашей карты ваш телефон отсортирован так, чтобы он выходил первым (0) до контакта (1)? Ваша функция уменьшения требует обратного порядка.

...