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.