2012-01-01 96 views
28

我正在写关于web应用程序的离线功能的论文。我的任务是通过带有服务器端关系数据库的Web应用程序和客户端与服务器之间的Ajax/JSON流量来显示离线存储的可能性。我的第一个实现在localStorage中使用了一种方法,将每个Ajax响应以请求URL作为键保存为值。该应用程序工作得很好。然而,在下一步中,我想(即论文要求)使用客户端数据库实现更高级的版本。由于服务器维护关系数据库,所以Web SQL数据库将是直观的选择。但是,正如我们所知,该标准已被弃用,我不想使用未来不确定的技术。因此,我想使用IndexedDB来实现客户端数据库逻辑。不幸的是,在阅读了很多网页上的材料后,这些材料大多数都是非常划伤表面(todo-notes应用程序等),但我仍然不知道如何继续。IndexedDB(关系等)的概念问题

我的任务看起来相当简单:在带有IndexedDB的客户端上实现服务器端数据库,以复制曾经从服务器获取的所有数据。的问题,这使得这远不如直接的是:

  • 服务器端的数据库关系,IndexedDB的是(或多或少)
  • 有同步客户端和服务器 - 没有直观的方式面向对象端数据库
  • 有是实现与外键实现,

现在在服务器上的JOIN在IndexedDB的关系没有直观的方式,我心里有一个概念,我真的很害怕开始实施。我想过为服务器数据库中的每个表创建一个对象存储,并手动为不同对象存储中的关系对象进行编程。简而言之,我的应用程序管理一所大学的课程,我有7个对象商店。

我要证明与来自服务器的JSON响应的例子我的想法(/ *这是注释* /):

{ "course": { /* course object */ 
    "id":1, 
    "lecturer": { "id":"1", /* lecturer object with many attributes */ }, 
    "semester": { "id":"1", /* semester object with many attributes */ }, 
    /* more references and attributes */ 
}} 

的算法存储与IndexedDB的的数据将存储每个对象,该对象适用于适当对象存储中的对象存储,并将这些对象替换为对这些对象的引用。例如,上述课程对象看起来像在对象存储“课程”以下内容:

{ "course": { /* course object */ 
    "id":1, 
    "lecturer": 
    { "reference": { /* reference to the lecturer in the object store 'lecturer' */ 
     "objectstore":"lecturer", 
     "id":"1" } 
    }, 
    "semester": 
    { "reference": { /* reference to the semester in the object store 'semester' */ 
     "objectstore":"semester", 
     "id":"1" } 
    } 
    /* more references and attributes */ 
}} 

的算法检索与IndexedDB的数据将然后执行以下操作(我有一个递归模式依稀记):

Retrieve the course object with id=1 from the object store 'course' 
For each reference object in the retrieved course object, do 
    Retrieve the object with id=reference.id from the object store reference.objectstore 
    Replace the reference object with the retrieved object 

可以清楚地看到,这个实现将是非常麻烦的,特别是由于索引资料的异步特性。它也会导致许多不同的事务到数据库只是为了检索一个课程对象,并且性能会受到很大的影响(我不知道IndexedDB事务的性能如何)。

我怎么能做到这一点更好,更简单?

我已经看过这些线程代表类似的问题:link1,link2。我没有看到任何更简单的解决方案。此外,我宁愿避免使用IndexedDB包装框架由于几个原因。

我也能想象得出我是完全错误的轨道与IndexedDB的我的问题上。

编辑:

我终于结束了追求我的方式来存储对象本身在IndexedDB的引用。这可能会导致一些性能问题的情况下,大量的数据与许多参考。但是,如果巧妙地使用,大多数情况下可以避免大量的迭代和数据库命中,并且不需要在内存或IndexedDB本身中存储复杂的数据库模式。

一般我必须说,我得到的是我误解与IndexedDB的动态和直主意,因为在某种程度上具结构数据库的印象。但无论如何,我用JavaScript实现了一切,它运行良好,没有任何不一致的机会。

+0

链接到删除已损坏,也不是问题的一部分。 – 2017-09-03 13:34:28

回答

21

我是新来IndexedDB的自己,但我也一直在思考了很多关于我如何将使用IndexedDB的为目的这个样子。我建议的第一件事,如果你还没有完成,就要看看其他键值/文档数据库(CouchDB,MongoDB等)是如何工作的,因为这实质上就是IndexedDB所在的数据库类型。

有几种不同的方法来处理文档数据库中的关系...至于与您的关系服务器端数据库同步,您可能需要创建某种自定义映射,因为一些关系的方法会对于IndexedDB不会非常干净地映射到关系数据库是有意义的。不过,我认为建立这样的映射是绝对可行的,而更大的问题是如何处理在IndexedDB的关系,所以这就是我把重点放在这里...

至于你提出的解决方案,我认为这实际上可以很好地工作,并且您可以编写一个简单的查询库来帮助巩固管道代码(更多内容在下面)。关键值存储的构建非常有效,可以通过关键字查找项目,因此对于每个相关对象来说,这样做可能不会像您想的那样低效......但是,我想出了另一个更好地使用索引的想法。 ..

首先,对于我提出的解决方案,您需要将“objectstore”元数据存储在“reference”对象本身以外的某个位置......它不一定需要存储在IndexedDB中所有;你可以只使用一个内存架构为:

var schema = { 
    Course: { 
     fields: [id, title], 
     relationships: { 
      lecturers: {objectstore: 'lecturer'}, 
      semester: {objectstore: 'semester'}, 
     } 
    }, 
    Lecturer: { ... } 
    ... 
}; 

(顺便说一句,你的JSON例子有错误...你不能有一个名为“引用”超过一个关键 - 它需要)

这使您可以直接在关系字段中存储ID值,以便您可以在它们上创建索引(为了清晰起见,我使用了字母前缀,即使实际上所有这些可能具有1的ID,因为ID值不需要在商店中是唯一的):

var course1 = { 
    id:'C1', 
    lecturers:['L1'], 
    semester:1 
}; 

var lecturer1 = { 
    id:'L1', 
    courses:['C1'] 
} 

var semester1 = { 
    id:'S1', 
    courses:['C1'] 
} 

您当然必须小心所有的存储/检索操作都是通过数据访问功能(例如,插入(),更新(),删除()),足够聪明,以确保关系总是正确地更新两端......实际上你可能不需要这取决于你打算如何查询数据,但它似乎这是一个好主意,因为您有时可能只想获取相关对象的ID(稍后查看或不查找),而不是实际检索它们。

假设您在讲师商店的“课程”字段中有一个索引。使用一个索引,你可以查找所有在一个特定课程ID相关联的讲师一举:

lecturerStore.index("courses").get("C1").onsuccess = … 

对于例如它没有多大意义,因为课程通常只有1-2个讲师,但考虑如何指数可以用来有效地查找了所有的课程,在特定的学期:

coursesStore.index("semester").get("S1").onsuccess = … 

注意的是,在讲师的例子(多对一对多的关系),该指数将需要指定作为“多元操作”,意思是说如果你有一个其值为一个数组的字段,数组中的每个元素都将被添加到索引中。 (请参阅https://developer.mozilla.org/en/IndexedDB/IDBObjectStore#createIndex ......我不确定浏览器支持的是什么)

我相信你也可以用索引做其他聪明的事情,使用游标和IDBKeyRange来帮助做某种“加入“操作。对于思路,看看这个链接,这表明处理关系的方式CouchDB的:

http://wiki.apache.org/couchdb/EntityRelationship

该链接还提到使用嵌入的文件,这是一件好事,你一定要考虑 - 不是所有的对象一定要有他们自己的对象存储,特别是对于“聚合”关系。 (顺便说一下,我不确定它对你有多大的帮助,因为它没有提供太多的查询方式,但是有人实际上在IndexedDB之上实现了一个类似CouchDB的数据库: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之上实现一个图形数据库,但我不确定它是多么实用。

祝你好运!

+0

我知道这很晚了,但是谢谢你的详细回答,这真的很有价值。我发布了一个答案,其中最初也包含了一些免费的东西,但不幸的是这些部分被删除了。 – Felix 2012-02-05 18:02:08

+0

很高兴你发现它有帮助!感谢您发表论文......我还没有机会看看它,但我当然会。 – 2012-03-09 06:28:40

+0

我刚刚发现了这个库,它似乎是一个有前途的方法来查询来自IndexedDB的数据以及许多其他数据库,使用相同的API: http://jaydata.org/ – 2013-02-22 23:00:20