Как я могу просмотреть избранные пользовательские документы пользователем в Couchdb map/reduce?

Моя база данных Couchdb в качестве основного типа документа выглядит примерно так:

{
   "_id" : "doc1",
   "type" : "main_doc",
   "title" : "the first doc"
   ...
}

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

{
   "_id" : "fav1",
   "type" : "favorite",
   "user_id" : "user1",
   "doc_id" : "doc1"
}

Достаточно просто создать представление с user_id в качестве ключа, чтобы получить список их любимых идентификаторов документов. Например:

function(doc) {
   if (doc.type == "favorite") {
      emit(doc.user_id, doc.doc_id);
   }
 }

Однако я хочу, чтобы список избранных отображал user_id, doc_id и заголовок из документа. Итак, выведите что-то вроде:

{ "key" : "user1", "value" : ["doc1", "the first doc"] }

person Jeremy Raymond    schedule 22.03.2010    source источник
comment
Или действительно не будет много накладных расходов для получения заголовков документов в отдельных запросах? У меня уже есть другое представление, которое выводит идентификатор документа и заголовок. Я пытался избежать повторного обращения к БД, чтобы получить название документа для каждого избранного.   -  person Jeremy Raymond    schedule 23.03.2010


Ответы (2)


В CouchDB 0.11 (только что выпущенном) функция include_docs=true позволяет искать любой документ в строке просмотра. Например:

function(doc) {
    if(doc.type == "favorite") {
        emit(doc.user_id, {_id: doc.doc_id});
    }
}

Когда вы запрашиваете представление с помощью include_docs=true, вы должны увидеть JSON следующим образом:

// ... normal stuff
rows: [
  {
    "key":"user1",
    "value":{"_id":"doc1"},
    "doc": {
      "_id" : "doc1",
      "type" : "main_doc",
      "title" : "the first doc"
      // ...
     }
  },
  {
    // another doc, etc...
  }
]
person JasonSmith    schedule 23.03.2010
comment
Это классная новая функция, но я не хочу возвращать весь документ. Мне просто нужен список любимых предметов только с названием. Мне нужен весь документ только в том случае, если пользователь выбирает просмотр документа. - person Jeremy Raymond; 23.03.2010
comment
Да, я понимаю. Также мое решение заставит вас, конечно, обновиться. Но я не уверен, как вы можете добиться того, чего хотите, без рефакторинга схемы. - person JasonSmith; 23.03.2010
comment
Я бы подумал о рефакторинге того, как устроены документы, чтобы учесть это. Какие-либо предложения? - person Jeremy Raymond; 24.03.2010
comment
Тогда я добавлю еще один ответ. - person JasonSmith; 24.03.2010
comment
Было бы здорово, если бы вы могли сделать include_docs, но затем указать подмножество полей документа, который вы хотите включить в представление. - person Jeremy Raymond; 25.03.2010

Если вы не можете использовать функцию include_docs=true с версией 0.11, тогда у вас должна быть вся информация под рукой, когда вы выдаете данные для своего представления/карты.

Вместо традиционного стиля «присоединения» рассмотрите возможность хранения списка «избранных» пользователей в main_doc документах.

{
   "_id" : "doc1",
   "type" : "main_doc",
   "title" : "the first doc",
   "favorited_by": ["user1", "user2"]
   // ...
}

Таким образом, когда ваше представление запускается, вы можете генерировать все на основе информации в этом одном документе.

function(doc) {
    if(doc.type == "main_doc") {
        for (var a in doc.favorited_by) {
            emit(doc.favorited_by[a], [doc._id, doc.title]);
        }
    }
}
person JasonSmith    schedule 23.03.2010
comment
Не могу ли я столкнуться с проблемами масштабируемости здесь? Если многие пользователи пытаются добавить этот же документ в избранное, у меня может возникнуть множество конфликтов. - person Jeremy Raymond; 25.03.2010
comment
Да, ты прав. Это компромисс, который зависит от ожидаемого использования. Другая идея состоит в том, чтобы хранить его по-другому: хранить ["doc_id", "Doc Title"] кортежей в пользовательском объекте. Для этого потребуется три обращения (1: получение основного документа; 2: получение документа пользователя, 3: обновление документа пользователя с помощью нового кортежа), однако вы можете уже иметь все эти документы под рукой в ​​нужное время. Я бы все же предпочел это по сравнению с несколькими поисками во время чтения через ваши документы в стиле соединения. - person JasonSmith; 25.03.2010
comment
Я надеялся на одну операцию чтения в любимых поисковых запросах. Я также пытался избежать копирования заголовка документа в другие документы, потому что, если заголовок обновляется в фактическом документе, скопированный заголовок устарел, или мне нужно найти и обновить все пользовательские документы, указав этот документ в качестве избранного. - person Jeremy Raymond; 25.03.2010
comment
Теперь у меня есть одно чтение в представлении, чтобы найти идентификаторы любимых документов для пользователя. Затем для каждого фаворита я ищу заголовок с другим чтением. - person Jeremy Raymond; 25.03.2010