Какой самый эффективный способ чтения отношений из базы данных pouchdb
Я использую pouchDb в электронном приложении. Данные были сохранены в базе данных postgres перед передачей в pouchDb. В некоторых случаях было несложно понять, как структурировать данные в форме документа.
Моя главная забота об отношениях. Например:
У меня есть тип данных Projects и у Projects много событий. Прямо сейчас у меня есть поле с именем project_id для каждого события. Поэтому, когда я хочу получить события для проекта с идентификатором 'project/1', я сделаю
_db.allDocs({
include_docs: true,
startkey: 'event',
endkey: 'event\uffff'
}).then(function(response){
filtered = _.filter(response['rows'], function(row){
return row['doc']['project_id'] == 'project/1'
});
result = filtered.map(function(row){
return row['doc']
})
});
Я прочитал это allDocs
является наиболее эффективным API, но удобнее ли иметь представление в этом случае?
С другой стороны, когда я показываю список со всеми проектами, каждый проект должен показывать количество событий, которые он имеет. По этому сценарию похоже, что мне придется снова запустить allDocs, с include_docs: false
чтобы подсчитать количество событий в проекте.
Разве видение улучшает эту ситуацию?
С другой стороны, я думаю о наличии массива со всеми идентификаторами событий в документе проекта, чтобы я мог легко посчитать, сколько в нем событий. В этом случае я должен использовать allDocs? Есть ли способ передачи массива идентификаторов в allDocs? Или лучше использовать цикл над этим массивом и вызывать get (id) для каждого идентификатора?
Этот способ более эффективен, чем первый?
Спасибо!
1 ответ
Хороший вопрос! Есть много способов обработки отношений в PouchDB. И, как и многие базы данных NoSQL, каждая из них даст вам компромисс между производительностью и удобством.
Система, которую вы описываете, не очень эффективна. В основном вы выбираете каждое событие в базе данных (O(n)
), а затем фильтрация в памяти. Если у вас много событий, то n
будет большим, то есть будет очень очень медленным.
У вас есть несколько вариантов здесь. Все они лучше, чем ваша текущая система:
- Связанные (или объединенные) документы в карте / уменьшить. Т.е. в твоем
map
функция, вы быemit()
проект_id
с для каждого события. Это создает вторичный индекс для того, что вы положили в качествеkey
вemit()
функция. - реляционный пакет, плагин, который работает с использованием префикса
_id
и работаетallDocs()
сstartkey
а такжеendkey
для каждого. Так было бы сделать одинallDocs()
чтобы получить проект, затем второйallDocs()
чтобы получить события для этого проекта. - Полностью отдельные базы данных, например
new PouchDB('projects')
а такжеnew PouchDB('events')
(Грубо говоря, они перечислены в порядке наименьшей производительности для большинства.)
# 1 является более производительным, чем система, которую вы описываете, хотя это все еще не очень быстро, потому что это требует создания вторичного индекса, а затем после этого по существу будет делать allDocs()
в базе данных вторичного индекса, а также в исходной базе данных (для получения связанных документов). Итак, в основном вы бежите allDocs()
три раза под капотом - один из которых находится на том, что вы излучали как key
что, кажется, вам не нужно, так что это будет просто потрачено впустую.
№ 2 намного лучше, потому что под капотом он работает два быстро allDocs()
запросы - один для извлечения проекта, а другой для извлечения событий. Это также не требует создания вторичного индекса; он может использовать бесплатный _id
индекс.
№ 3 также требует два allDocs()
звонки. Так почему же он самый быстрый? Что ж, интересно, это из-за того, что IndexedDB упорядочивает операции чтения / записи под капотом. Допустим, вы пишете обоим 'projects'
а также 'events'
, IndexedDB будет выполнять сериализацию этих двух записей, поскольку не может быть уверенности в том, что они не будут изменять одни и те же документы. (Тем не менее, когда дело доходит до чтения, два запроса могут выполняться одновременно в любом случае - по крайней мере, в Chrome. Я полагаю, что Firefox фактически сериализует чтения.) Таким образом, в основном, если у вас есть две совершенно разные PouchDB, представляющие две совершенно разные IndexedDB, тогда и чтение, и запись могут выполняться одновременно.
Конечно, в случае отношений родитель-ребенок вы не можете заранее знать идентификаторы дочерних элементов, поэтому вам все равно придется выбрать родительский элемент, а затем получить дочерние элементы. Так что в этом случае нет разницы в производительности между #2 и #3.
В вашем случае, я бы сказал, что лучший выбор, вероятно, №2. Это хороший компромисс между идеей и удобством, тем более что relational-pouch
Плагин уже делает работу за вас.