DexieJS和IndexedDB中的完全动态索引规范

时间:2018-06-14 03:57:13

标签: indexeddb dexie

对于我的应用程序,我希望用户能够为表指定索引列。

我认识到为了做到这一点,我需要关闭数据库,指定新版本,然后再次打开它。尽量减少这样做的影响我将应用程序的这个自定义部分放在自己的数据库中。

这是我如何做到这一点的一个例子。

import Dexie from 'dexie';

const db = new Dexie("CustomPeople");

db.version(1).stores({
  people: '++id'
});

function testColumnAdd() {

  modifyColumns(['firstName'])
    .then(() => {

      db.people.add({
        firstName: 'John'
      });

    })
    .then(() => {

      return modifyColumns(['firstName', 'lastName']);

    })
    .then(() => {

      db.people.add({
        firstName: 'John',
        lastName: 'Smith'
      });

    });

}

function modifyColumns(columns) {

  return db.open()
    .then(() => {

      const originalVersion = db.verno;

      console.log('original version: ' + originalVersion);

      db.close();

      return originalVersion;

    })
    .then((originalVersion) => {

      const newVersion = originalVersion + 1;

      console.log('adding columns ' + columns.join(','));

      console.log('new version version ' + newVersion);

      db.version(newVersion).stores({
        leads: '++id,' + columns.join(',')
      });

      return db.open();

    });

}

每次调用testColumnAdd()时,这似乎都能正常工作。

但是,在页面重新加载后,testColumnAdd()的第一个触发器会出现以下异常。

Unhandled rejection: VersionError: The requested version (10) is less than the existing version (70).

这绝对是有道理的,因为Dexie最初可以看到版本1.是否有一种方法可以阅读当前版本并使用它?

一般来说,有更好的方法来处理用户定义的索引吗?

2 个答案:

答案 0 :(得分:0)

Dexie有一个动态模式。通过省略db.version(x)的规范来启用它。它基本上将数据库打开到当前版本。

new Dexie("CustomPeople").open().then (db => {
    console.log("Version", db.verno);
    console.log("Tables", db.tables.map(({name, schema}) => ({
        name,
        schema
    }));
});

但是当您需要修改模式(或最初创建模式)时,您必须按照自己的意愿进行操作 - 在打开之前指定db.version(db.verno + 1)。

需要重新打开数据库以更改架构的原因是IndexedDB本身的限制/功能。

编辑:我刚刚更新了文档:http://dexie.org/docs/Dexie/Dexie.open()#dynamic-schema-manipulation

答案 1 :(得分:0)

我不确定这是否最初是Dexie的意图,但是我发现了围绕现有数据库初始化的另一种方法。

出于其他原因,我需要将列的定义存储在单独的数据库中。当我加载现有数据库时,我只是基于该元数据构建正确的版本。

const dbName = 'CustomPeople';

const exists = await Dexie.exists(dbName);

if (exists) {

    var db = new Dexie(dbName);

    const dynamicDB = await db.open();

    const existingVersionNumber = dynamicDB.verno;

    const columns = await ExternalDBService.getColumns();

    db.close();

    db = new Dexie(dbName);

    db.version(existingVersionNumber).stores({
        People: columns
    });

    return db.open();

} else {

    db = new Dexie(dbName);

    db.version(1).stores({
        People: []
    });

    db.open();

}