Ответ 1
Отличный вопрос. Вы определяете несколько очень важных причин, по которым использование "нормализованной" модели данных (разные типы документов со ссылками) является оптимальной моделью:
- У вас есть отношение "многие ко многим" между пользователями < == > lists < == > games.
- Отношения "один ко многим" легко представить в одном документе, который использует контейнер для части "много", но они становятся большими, и у вас могут быть конфликты concurrency.
- Расширение модели с одним документом для хранения отношения "многие ко многим" несостоятельно.
- В целом, неизменность документа отлично подходит для параллельных систем. В CouchDB вы делаете это точно так же, как вы отметили, сохраняя документы "write-once", которые представляют собой край в вашем графике, а затем используют вторичные индексы для восстановления частей ссылок, которые вы хотите, и для получения требуемой информации в одном Запрос запроса API.
Вы также правы, что решение здесь - это "соединение на стороне карты" (для заимствования из сообщества hadoop). В основном вы хотите использовать разные строки на выходе карты для представления разных частей информации. Затем вы можете использовать запрос диапазона (startkey/endkey), чтобы запросить только ту часть результата карты, которая вам нужна, и, вуаля, ваше материализованное представление таблицы "join". Тем не менее, одна часть головоломки, которую вы не нашли в документации, такова:
http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents
Первая строка:
"Если вы испускаете значение объекта, которое имеет {'_id': XXX}, то include_docs = true будет извлекать документ с идентификатором XXX, а не документом, который был обработан для испускания пары ключ/значение."
говорит все. Это как разыменовать указатель на связанный документ, который вы сохранили с помощью внешнего ключа. Затем вы комбинируете это с использованием составных клавиш (ключей, которые являются массивами JS) и правил свертывания представления:
Итак, чтобы ваши строки просмотра были отсортированы так:
["list_1"], null
["list_1", "game"], {"_id":"game_1234"}
["list_1", "game"], {"_id":"game_5678"}
["list_2"], null
["list_2","game"], {"_id":"game1234"}
["list_3"], null
...
Объединяя это вместе с вашей существующей моделью данных, вот несколько (непроверенных) псевдокодов, которые должны сделать трюк:
function(doc) {
if (doc.type=="list") {
//this is the one in the one-to-many
emit( [doc._id]),);
}
else if (doc.type=="relationship") {
//this is the many in the one-to-many
//doc.list_id is our foreign key to the list. We use that as the key
//doc.game_id is the foreign key to the game. We use that as the value
emit( [doc.list_id,'game'], {'_id': doc.game_id});
}
}
Наконец, вы должны запросить это с ключом startkey/endkey, чтобы вы получили все строки, которые начинаются с list_id, который вас интересует. Он будет выглядеть примерно так:
curl -g 'https://usr:[email protected]/db/_design/design_doc_name/_view/view_name?startkey=["123"]&endkey=["123",{}]&include_docs=true'
Параметр -g
указывает curl not glob, что означает, что вам не нужно разыменовывать квадратные скобки и т.д., а параметр include_docs=true
будет следовать указателю на внешний ключ, который вы указали с помощью game_id
в документе relationship
.
Анализ:
- Вы используете по существу неизменяемые документы для хранения изменений состояния, и вы даете базе данных вычислить общее состояние для вас. Это прекрасная модель в масштабе и один из наших самых успешных моделей.
- Очень эффективен для добавления или удаления списков.
- Отличные масштабирующие свойства при высоком уровне concurrency
- В Cloudant (и CouchDB v2.0) у нас еще нет согласованности "read-your-write" для вторичных индексов. В списке приоритетов он высок, но есть потенциальные угловые случаи, когда в сценариях сбоев или при высокой нагрузке вы можете не видеть непосредственной согласованности между первичными и вторичными индексами. Короче говоря, кворум используется для первичных индексов, но кворум не является жизнеспособной моделью для вторичных индексов, поэтому разрабатывается другая стратегия согласования.