Dexie.js Autoincrement Primary Key - does it ever

2019-07-26 06:56发布

In Dexie.js you can create a store with an auto-incrementing key

    let db = new Dexie("nav_api");
    db.version(1).stores({
        jobs: '++id, json'
    });

So to test, I created 14 objects in the db via db.jobs.put({json: '[]'}), and all their keys came out as expected, started at 1 up to 14. Then deleted some of the later ones, db.jobs.where('id').above(6).delete(), and added another one to the db, and its index was 15.

Is there any way to reset the index to 0? I was using it for ordering, and I'm not sure what happens when the value gets incredibly large -- does it eventually wrap back around to 0?

On the other hand, it's also probably not something I need to worry about. Depending on how high the '++id' field can be, and I'm assuming it will be in the billions, it would be many many years (many lifetimes) before it was ever something to worry about. So maybe I should just ignore it.

[edit] I tried clearing the table, db.jobs.clear() and then putting a new row in the table, but again it used the next index after. I can't find a way to fully delete a table, however I can fully delete an entire database but I don't really want to do that.

2条回答
霸刀☆藐视天下
2楼-- · 2019-07-26 07:36

The accepted answer solves the question just partially and doesn't provides an actual solution to the problem in form of code. In my oppinion it isn't a good idea to count up the auto-incremented integers without need. For sure one would need huge sets of data, but high numbers could be irritating to users, especially if they ask themself where the previous id's are.

I mostly copied over this script from the Dexie-Developer dfahlander and altered it to achieve what was asked for. Beware that cloning a database forth and back could take a long time to run, depending on the size of your database. The bulkAdd isn't wrapped in a transaction, so on errors the script could break. That said I've to warn you to make a backup before you execute this function.

function refreshIndices(database){

  const databases = [database, database+'_temp'];
  // Loop 2 times - move database forth and back
  (function next(cnt, max){
    if(cnt++ >= max){ doSomething(); return;}
    // ! turns 1 into 0 and vice-versa / + turns boolean into integer
    var sdb = new Dexie(databases[cnt-1]),
        ddb = new Dexie(databases[+!(cnt-1)]);

    sdb.open().then(()=>{
        // Clone scheme
        const schema = sdb.tables.reduce((result,table)=>{
          result[table.name] = (
            [table.schema.primKey]
            .concat(table.schema.indexes)
            .map(indexSpec => indexSpec.src)
            ).toString();
          return result;
        }, {});
        ddb.version(sdb.verno).stores(schema);

        // Clone Data and delete source-database
        return sdb.tables.reduce(
          (result, table) => result
            .then(() => table.toArray())
            .then(rows => ddb.table(table.name).bulkAdd(rows) ),
          Promise.resolve()     
        ).then((x)=>{ sdb.delete(); ddb.close(); next(cnt,max); })
    })
  })(0, databases.length);
}

This function must be called with the database name as string, which you want to clone. (i.e. refreshIndices('dbname')) The database must exist. The function iterates 2 times. On first run, the source database gets cloned into a temporary database and then the source database gets deleted. When done the function runs again and clones the temporary database into the source database and then deletes the temporary database. No overhead will be left.

For debugging purposes I would alter

.then(rows => ddb.table(table.name).bulkAdd(rows) )

to

.then((rows) => { 
    console.log("Cloning "+table.name);
    ddb.table(table.name).bulkAdd(rows)
}) )

This function should work out of the Box with Dexie.js. Database creation can also be followed via Developer Tools (Chrome) => Application => IndexedDB => __dbnames => Refresh.

查看更多
Animai°情兽
3楼-- · 2019-07-26 07:42

The IndexedDB spec has more info.

You probably won't hit the upper limit:

The current number is always a positive integer less than or equal to 253 (9007199254740992) + 1.

And there is no way to reset it, other than deleting the object store and recreating it:

The current number for a key generator never decreases, other than as a result of database operations being reverted. Deleting a record from an object store never affects the object store’s key generator. Even clearing all records from an object store, for example using the clear() method, does not affect the current number of the object store’s key generator.

查看更多
登录 后发表回答