IndexedDB的概念问题(关系等) [英] Conceptual problems with IndexedDB (relationships etc.)

查看:132
本文介绍了IndexedDB的概念问题(关系等)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的任务似乎相当简单:使用IndexedDB在客户端上实现服务器端数据库,以复制曾经从服务器获取的所有数据 。问题远远不那么简单:




  • 服务器端数据库是关系型的,IndexedDB是(或多或少)对象 - 面向对象

  • 没有直观的方法来同步客户端和服务器端数据库

  • 没有直观的方法来实现关系使用外键和服务器上的JOIN实现的IndexedDB



现在,我有一个概念,我我真的害怕开始实施。我考虑过为服务器数据库中的每个表创建一个对象存储,并手动编写不同对象存储中的关系对象。在我的申请中,简而言之,管理大学的课程,我有7个对象店。



我想通过服务器的JSON响应示例来展示我的想法(/ *这些是注释* /):

  {course:{/ * course object * / 
id:1,
讲师:{id: 1,/ *讲师对象有很多属性* /},
学期:{id:1,/ *学期对象有很多属性* /},
/ *更多引用和属性* /
}}

存储数据的算法IndexedDB 会将适用于对象存储的每个对象存储在相应的对象库中,并使用对这些对象的引用替换对象。例如,上面的课程对象在对象商店课程中看起来如下所示:

  {course:{ / *课程对象* / 
id:1,
讲师:
{参考:{/ *参考对象店'讲师'* / $中的讲师b $ bobjectstore:讲师,
id:1}
},
学期:
{reference:{/ *参考到对象商店'学期'的学期* /
对象商店:学期,
id:1}
}
/ *更多参考和属性* /
}}

使用IndexedDB检索数据的算法然后执行以下操作(我有一个模糊的递归模式):

 检索id = 1的课程对象来自对象库'course'
对于检索到的课程对象中的每个参考对象,执行
检索id = reference.id的对象在对象库reference.objectstore
用检索到的对象替换引用对象

它是清楚地看到这种实现非常麻烦,特别是由于IndexedDB的异步特性。它还会导致许多不同的数据库事务只是为了检索一个课程对象,性能会受到很大影响(我真的不知道IndexedDB事务的性能是什么样的)。



我怎样才能做得更好更简单?



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



我还可以想象我完全在使用IndexedDB的错误轨道上问题。



编辑:



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



一般来说,我必须说,我得到的印象是我在某种程度上将IndexedDB作为无模式数据库误解为动态和直接的想法。但无论如何,我用JavaScript实现了一切,它工作正常,没有任何不一致的机会。

解决方案

我是新的我自己也参与过IndexedDB,但我也一直在考虑如何将IndexedDB用于这样的目的。我建议的第一件事是,如果你还没有这样做,就要看看其他键值/文档数据库(CouchDB,MongoDB等)是如何工作的,因为它基本上就是IndexedDB的数据库类型。 / p>

处理文档数据库中的关系有几种不同的方法...为了与关系服务器端数据库同步,您可能需要创建某种自定义映射是因为某些对IndexedDB有意义的关系方法不会非常干净地映射到关系数据库。但是,我认为设置这样的映射肯定是可行的,更大的问题是如何处理IndexedDB中的关系,所以这就是我要关注的......



<对于您提出的解决方案,我认为它实际上可以正常工作,您可以编写一个简单的查询库来帮助整合管道代码(更多内容见下文)。键值存储的构建非常有效地按键查找项目,因此对每个相关对象执行此操作可能不会像您想象的那样低效...但是,我提出了另一个更好地利用索引的想法。 ..



首先,对于我提出的解决方案,您需要将objectstore元数据存储在reference对象本身以外的某个位置...它不会甚至根本不需要存储在IndexedDB中;你可以只使用内存模式:

  var schema = {
课程:{
字段:[id,title],
关系:{
讲师:{objectstore:'讲师'},
学期:{objectstore:'semester'},
}
},
讲师:{...}
...
};

(顺便说一句,你的JSON示例有一个错误...你不能超过一个叫做引用的键 - 它需要是一个引用数组。)



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

  var course1 = {
id:'C1',
讲师:['L1'],
学期:1
};

var讲座1 = {
id:'L1',
课程:['C1']
}

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

当然,您必须小心所有存储/检索操作都是通过数据访问功能(例如insert(),update(),delete())进行的,这些功能足够智能以确保关系是总是在两端都正确更新...实际上你可能不需要它,这取决于你打算如何查询数据,但它似乎是一个好主意,因为你有时可能只想获得相关对象的ID(看起来以后,或者不是实际检索它们。



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

 讲授者商店指数(课程)。得到(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



该链接还提到使用嵌入式文档,这是某种东西你应该考虑 - 并非所有对象都必须拥有自己的对象存储,特别是对于聚合关系。



(顺便说一句,我不确定它对你有多大帮助,因为它没有提供很多查询方式,但实际上有人在IndexedDB上实现了类似CouchDB的数据库: https://github.com/mikeal/pouchdb



除索引外,实现缓存机制可能也很有帮助。



现在,为了简化查询过程,我知道你提到不想使用aw说唱歌手库...但我对可以创建的方便API有了一个想法,它会接受这样的对象:

  //选择'Wilkins教授'教授的所有课程
{
来自:'讲师',//在讲师店打开游标
其中:function(讲师){return lecturer.name = ='威尔金斯教授'},//评估每个项目找到
选择:函数(讲师){return lecturer.courses},//从上一步返回什么
//这应该在推断中这种情况,但只是为了说清楚...
eagerFetch:function(讲师){return lecturer.courses}
}

我不确定实施起来有多难,但看起来它似乎会让生活更轻松。



我已经漫长了很长时间,但我想提到最后一件事,那就是我一直在考虑借用图表数据库中的一些想法,因为他们在处理关系方面要好得多。韩文档数据库,我认为可以在IndexedDB上实现图形数据库,我还不确定它有多实用。



祝你好运!


I'm writing a thesis about offline abilities of web applications. My task is to show the possibilities of offline storage through a web application with a server-side relational database and Ajax/JSON traffic between client and server. My first implementation used an approach with localStorage, saving each Ajax response as value with the request URL as key. The app works just fine. In the next step however, I want to (i.e. the thesis requires) implement a more advanced version with a client-side database. Since the server maintains a relational database, Web SQL Database would have been the intuitive choice. But, as we know, the standard is deprecated and I don't want to use a technology whose future is uncertain. Thus, I want to use IndexedDB to implement client-side database logic. Unfortunately, after reading a lot of material on the web that mostly keeps very much scratching the surface (todo-notes applications etc.), I still don't know how to proceed.

My task seems rather straightforward: implement the server-side database on the client with IndexedDB to replicate all data that was once fetched from the server. The problems, which make this far less straightforward are:

  • The server-side database is relational, IndexedDB is (more or less) object-oriented
  • There is no intuitive way to synchronize client- and server-side databases
  • There is no intuitive way to implement the relationships in IndexedDB that are implemented with foreign keys and JOINs on the server

Right now, I have a concept in mind which I'm really afraid to start to implement. I thought about creating an object store for every table in the server-database and program the relations objects in different object stores manually. In my application, which, in short, manages courses of a university, I'd have 7 object stores.

I want to demonstrate my idea with an example for a JSON response from the server (/* these are comments */):

{ "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 */
}}

The algorithm to store the data with IndexedDB would store each object that applies to an object store in the appropriate object store and replace the objects with references to these objects. For example, the above course object would look like the following in the object store 'course':

{ "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 */
}}

The algorithm to retrieve data with IndexedDB would then do the following (I have a recursive pattern vaguely in mind):

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

It is clearly visible that this implementation would be really cumbersome, especially due to the asynchronous nature of IndexedDB. It would also result in many different transactions to the database just to retrieve a course object and performance would suffer a lot (I don't really know what the performance of IndexedDB transactions looks like anyway).

How could I do this better and simpler?

I already looked at these threads which represent similar problems: link1, link2. I don't see any simpler solutions in these. Moreover, I'd prefer to avoid using an IndexedDB wrapper framework due to several reasons.

I could also imagine that I'm totally on the wrong track with IndexedDB for my problem.

Edit:

I finally ended up pursuing my approach to store the references in the objects themselves in the IndexedDB. This can result in some performance problems in cases of large amounts of data with many references. If used smartly, however, tremendous amounts of iteration and database hits can be avoided in most cases, and there is no need to store a complex database schema in memory or in the IndexedDB itself.

Generally I must say, that I get the impression that I'm misinterpreting the dynamic and straight idea with IndexedDB as a schemaless database in some way. But whatever, I implemented everything in JavaScript, it works fine and there is no chance for any inconsistencies.

解决方案

I'm new to IndexedDB myself but I too have been thinking a lot about how I would use IndexedDB for purposes like this. The first thing I would suggest, if you haven't done it already, is to look at how other key-value / document databases (CouchDB, MongoDB, etc.) work, since that's essentially the type of database that IndexedDB is.

There are several different approaches to handling relationships in a document database...as to synchronizing with your relational server-side database, you will probably need to create some kind of custom mapping because some of the approaches to relationships that would make sense for IndexedDB will not map very cleanly to a relational database. However, I think setting up such a mapping is definitely doable, and the bigger issue is how to handle relationships in IndexedDB, so that's what I'll focus on here...

As to your proposed solution, I think it could actually work well, and you could write a simple querying library that helped consolidate the plumbing code (more on that below). Key-value stores are built to be very efficient at looking up items by key, so doing so for each related object might not be as inefficient as you think...however, I came up with another idea that makes better use of indexes...

First, for my proposed solution, you'd need to store the "objectstore" metadata somewhere other than within the "reference" object itself...it doesn't necessarily even need to be stored in IndexedDB at all; you could just use an in-memory schema for that:

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

(By the way, your JSON example has an error...you can't have more than one key called "reference" - it would need to be a "references" array.)

This frees you up to store the ID values directly in the relationship fields, so that you can create indexes on them (I've used letter prefixes for clarity even though in reality all of these would probably have an ID of 1, since ID values don't need to be unique across stores):

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

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

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

You would, of course, have to be careful that all storage/retrieval operations happened through data access functions (e.g. insert(), update(), delete()) that were smart enough to ensure that the relationships were always updated correctly on both ends...actually you may not need that depending on how you plan to query the data, but it seems like a good idea since you might sometimes just want to get the IDs of the related objects (to be looked up later, or not) rather than actually retrieving them.

Let's say you have an index on the "courses" field in the lecturer store. Using an index, you could look up all of the lecturers associated with a particular course ID in one fell swoop:

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

For that example it doesn't matter much because courses will generally only have 1-2 lecturers, but consider how an index could be used to efficiently look up all the courses in a particular semester:

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

Note that in the lecturer example (a many-to-many relationship), the index would need to be specified as "multientry," meaning that if you have a field whose value is an array, each element of the array will be added to the index. (See https://developer.mozilla.org/en/IndexedDB/IDBObjectStore#createIndex ...I'm not sure what the browser support is on this.)

And I'm sure you could do other clever things with indexing too, using cursors and IDBKeyRange to help do some sort of "join" operation. For ideas, check out this link, which demonstrates ways of handling relationships in CouchDB:

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

That link also mentions using embedded documents, which is something you should definitely consider -- not all objects necessarily need to have their own object store, especially for "aggregation" relationships.

(By the way, I'm not sure how helpful it would be to you since it doesn't provide much in the way of querying, but someone has actually implemented a CouchDB-like database on top of IndexedDB: https://github.com/mikeal/pouchdb)

In addition to indexes, implementing a caching mechanism would probably help a lot too.

Now, as to simplifying the querying process, I know you mentioned not wanting to use a wrapper library...but I had an idea about a convenient API that could be created, that would accept an object like this:

//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 }
}

I'm not sure how difficult it would be to implement, but it definitely seems like it would make life easier.

I've rambled long enough, but I wanted to mention one last thing, which is that I've also been thinking about borrowing some ideas from graph databases, since they're much better at handling relationships than document databases, and I do think it would be possible to implement a graph database on top of IndexedDB, I'm just not yet sure how practical it would be.

Good luck!

这篇关于IndexedDB的概念问题(关系等)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆