Я новичок в IndexedDB, но я тоже много думал о том, как бы я использовал IndexedDB для подобных целей.Первое, что я хотел бы предложить, если вы еще этого не сделали, - это посмотреть, как работают другие базы данных ключ-значение / документы (CouchDB, MongoDB и т. Д.), Поскольку это, по сути, тип базы данных IndexedDB.
Существует несколько различных подходов к обработке отношений в базе данных документов ... что касается синхронизации с вашей реляционной серверной базой данных, вам, вероятно, потребуется создать какое-то пользовательское отображение, потому что некоторые из подходов к отношениям, которыебыло бы целесообразно, чтобы IndexedDB не очень точно отображал реляционную базу данных.Тем не менее, я думаю, что создание такого сопоставления определенно выполнимо, и большая проблема заключается в том, как обрабатывать отношения в IndexedDB, поэтому я сосредоточусь на этом здесь ...
Что касается предложенного вами решения, яЯ думаю, что на самом деле это может работать хорошо, и вы могли бы написать простую библиотеку запросов, которая бы помогала консолидировать программный код (подробнее об этом ниже).Хранилища значений ключей созданы для того, чтобы очень эффективно искать элементы по ключу, поэтому выполнение каждого связанного объекта может быть не таким неэффективным, как вы думаете ... однако я пришел к другой идее, которая лучше использует индексы...
Во-первых, для моего предложенного решения вам нужно будет хранить метаданные «хранилища объектов» где-то, кроме самого «ссылочного» объекта ... его не обязательно даже сохранять вIndexedDB вообще;для этого вы можете просто использовать схему в памяти:
var schema = {
Course: {
fields: [id, title],
relationships: {
lecturers: {objectstore: 'lecturer'},
semester: {objectstore: 'semester'},
}
},
Lecturer: { ... }
...
};
(Кстати, в вашем примере JSON есть ошибка ... вы не можете иметь более одного ключа с именем "reference" - этодолжен быть массив «reference».)
Это освобождает вас от необходимости хранить значения ID непосредственно в полях отношений, так что вы можете создавать индексы для них (я использовал буквенные префиксы для ясности дажехотя в действительности все они, вероятно, имели бы идентификатор 1, поскольку значения идентификаторов не должны быть уникальными для разных магазинов):
var course1 = {
id:'C1',
lecturers:['L1'],
semester:1
};
var lecturer1 = {
id:'L1',
courses:['C1']
}
var semester1 = {
id:'S1',
courses:['C1']
}
Вы, конечно, должны быть осторожны, чтобы все хранилище/ операции извлечения выполнялись с помощью функций доступа к данным (например, insert (), update (), delete ()), которые были достаточно умными, чтобы гарантировать, что отношения всегда корректно обновлялись на обоих концах ... на самом деле это может не понадобиться в зависимости от того, каквы планируете запрашивать данные, но это кажется хорошей идеей, поскольку иногда вы можете просто захотеть получить идентификаторы связанных объектов (которые будут найдены позже или нет), а неctually извлечь их.
Допустим, у вас есть индекс в поле «курсы» в магазине лекторов.Используя индекс, вы можете найти всех лекторов, связанных с определенным идентификатором курса, одним махом:
lecturerStore.index("courses").get("C1").onsuccess = …
Для этого примера это не имеет большого значения, потому что курсы обычно имеют только 1-2лекторам, но подумайте, как можно использовать индекс для эффективного поиска всех курсов в конкретном семестре:
coursesStore.index("semester").get("S1").onsuccess = …
Обратите внимание, что в примере лектора (отношение многих ко многим) индекс будетнеобходимо указать как «multientry», что означает, что если у вас есть поле, значение которого является массивом, каждый элемент массива будет добавлен в индекс.(См. https://developer.mozilla.org/en/IndexedDB/IDBObjectStore#createIndex ... Я не уверен, что поддержка браузера на этом.)
И я уверен, что вы могли бы сделать и другие умные вещи с индексацией, используя курсоры и IDBKeyRangeчтобы помочь сделать какую-то операцию «присоединиться».Для идей, перейдите по этой ссылке, которая демонстрирует способы обработки отношений в CouchDB:
http://wiki.apache.org/couchdb/EntityRelationship
В этой ссылке также упоминается использование встроенных документов, что вы обязательно должны учитывать - невсе объекты обязательно должны иметь свое собственное хранилище объектов, особенно для отношений «агрегации».
(Кстати, я не уверен, насколько это будет полезно для вас, так как он не дает много вспособ запроса, но кто-то фактически реализовал CouchDB-подобную базу данных поверх IndexedDB: https://github.com/mikeal/pouchdb)
В дополнение к индексам, реализация механизма кэширования, вероятно, тоже очень поможет.
Теперь, что касается упрощения процесса запроса, я знаю, что вы упомянули, что не хотите использовать библиотеку-обертку ... но у меня была идея об удобном API, который можно было бы создать, который бы принимал такой объект:
//select all courses taught by 'Professor Wilkins'
{
from: 'lecturer', //open cursor on lecturer store
where: function(lecturer) { return lecturer.name=='Professor Wilkins' }, //evaluate for each item found
select: function(lecturer) { return lecturer.courses }, //what to return from previous step
//this should be inferred in this case, but just to make it clear...
eagerFetch: function(lecturer) { return lecturer.courses }
}
Я не уверен, насколько сложно это было бы реализовать, но определенно кажется, что это облегчит жизнь.
Я бродил достаточно долго, но я хотел бы упомянуть еще одну вещь: я также думал о заимствовании некоторых идей из графовых баз данных, поскольку они гораздо лучше обрабатывают отношения, чем базы данных документов, и Я действительно думаю, что было бы возможно реализовать графическую базу данных поверх IndexedDB, я просто еще не уверен, насколько это будет практично.
Удачи!