Какой самый эффективный способ чтения отношений из базы данных 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 будет большим, то есть будет очень очень медленным.

У вас есть несколько вариантов здесь. Все они лучше, чем ваша текущая система:

  1. Связанные (или объединенные) документы в карте / уменьшить. Т.е. в твоем map функция, вы бы emit() проект _idс для каждого события. Это создает вторичный индекс для того, что вы положили в качестве key в emit() функция.
  2. реляционный пакет, плагин, который работает с использованием префикса _idи работает allDocs() с startkey а также endkey для каждого. Так было бы сделать один allDocs() чтобы получить проект, затем второй allDocs() чтобы получить события для этого проекта.
  3. Полностью отдельные базы данных, например 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 Плагин уже делает работу за вас.

Другие вопросы по тегам