Storage / LokiJS


#1

Hi!

I’d like to share my experience with persistence storage with ionic

Offline applications have to store a lot of (complex or not) objects.

Solution 1 : https://github.com/TheCocoaProject/cordova-plugin-nativestorage
But we can read in “When not to use the plugin” section : For storing many objects please consider trying a database-based strategy

Solution 2 : https://ionicframework.com/docs/storage/
Can be a solution but in my case I have to search data with complex parameters

Solution 3 : https://github.com/litehelpers/Cordova-sqlite-storage
Good solution but it’s a pity to write some old SQL queries instead of using the power of javascript such as NoSQL database.

Solution 4 : http://lokijs.org : LokiJS is an in-memory database with persistable NoSQL db for Cordova / Phonegap / Nativescript
OK, but how to make persistable data, which adapter to use?
I already use this library with ionic 1 and file adapter, but very documention exist for angular2+ that’s why I share my experience.

Which adapter to use : https://github.com/techfort/LokiJS/wiki/LokiJS-persistence-and-adapters

LokiIndexedAdapter is a good agreement. Available to store up to 60Mb an supported by major OS/browser version.

This is how I implement it with ionic3/Angular5

First add lokijs package in the app root directory

npm install lokijs --save

Import it and the indexDB adapter in a separated provider :

import 'rxjs/add/operator/toPromise';
import { Injectable } from '@angular/core';
import * as Loki from 'lokijs';
import * as LokiIndexedAdapter from 'lokijs/src/loki-indexed-adapter'

@Injectable()
export class Database {
  db: any;
  cat: any;

  constructor() {
  }

  loadDB() {
    let promise = new Promise((resolve, reject) => {
      let adapter = new LokiIndexedAdapter();
      this.db = new Loki('CAT.db', {
        autosave: true,
        //autoload: true,
        autosaveInterval: 4 * 1000,
        adapter: adapter
      });


      this.db.loadDatabase({}, (err) => {
        if (err) {
        }
        else {
          console.log("database loaded.");
          this.cat = this.db.getCollection('CAT');
          resolve();
        }
      });
    });
    return promise;

  }

  initDB() {
    let promise = new Promise((resolve, reject) => {
      let seq = this.api.get('initGame', param).share();
      seq.subscribe((res: any) => {
        let cat = this.db.getCollection('CAT');
        if (cat) {
          this.db.removeCollection('CAT');
        }
        this.cat = this.db.addCollection('CAT', { 'unique': 'i' });
        this.cat.insert(res.items);
        resolve(true);
      }, err => {
        console.error('ERROR', err);
      });
    });
    return promise;
  }


  update(item) {
    this.cat.update(item);
  }

}

Then you easily call this provier from other pages/providers :


let loading = this.loadingCtrl.create({
	content: 'Loading...'
});

loading.present();

this.database.initDB().then(() => {
	loading.dismiss();
	this.navCtrl.setRoot('WelcomePage', {}, {
		animate: true,
		direction: 'forward'
	});
});

Hoping that this can be helpful :grinning:


#2

Thanks!, I was looking for something like this.
However is there no need for extra Storage like Storage, localforage etc, indexedDB, ?
Or have I miss something here ?

Secondly
I guess this not exist yet, But is it possible to build some kind of a sync adapter on top of it, so it could upload data from lokijs to server and back again in a bidirection ? Trying to achieve something like firebase/firestore behavior without using to much frameworks for that.

My hope is to using lokijs for this and combine that with perhaps socket in order to upload/download to/from server.

Any thoughs/tips/experience you could provide on this ?

Thanks again!