【问题标题】:Fully dynamic index specification in DexieJS and IndexedDBDexieJS 和 IndexedDB 中的完全动态索引规范
【发布时间】:2018-11-23 18:04:11
【问题描述】:

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

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

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

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。有没有办法让我可以阅读当前版本并使用它?

有没有更好的方法来处理用户定义的索引?

【问题讨论】:

    标签: indexeddb dexie


    【解决方案1】:

    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

    【讨论】:

    • 这很有帮助。但是,当我尝试这个时,我注意到导入的数据库提供的数据库实例不完整。我无法从动态加载的数据库中调用 db.friends.add({name: 'John'})。我是否需要手动读取架构并构建新版本?
    • 你必须使用 db.table('friends') 而不是 db.friends 因为 Dexie 不会静态调整其 api 以适应动态打开的实例
    【解决方案2】:

    我不确定这是否是 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();
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-11
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 2021-07-06
      • 1970-01-01
      • 2013-03-08
      相关资源
      最近更新 更多