Dexie.js: Dexie DB within a web worker

Created on 16 Jan 2019  路  4Comments  路  Source: dfahlander/Dexie.js

First of all, thank you for this IDB wrapper, the API is rich and well documented.

I am having some issues with opening (with the purpose of writing) an existing dexie database from a web worker (same origin).
The goal is to fetch a significant amount of data (500k+) and then write in chunks to indexedDB. The fetch part works well in the worker, however, opening the existing database fails.
I have also tried to create a new database from the worker, and then initiated a db.tableName.bulkPut but that new database would not even be created (not visible in Chrome > devTools > Applications tab)

Here's what I am currently doing:

  • In window context:

import Dexie from "dexie";
const db = new Dexie("myDB");
db.version(1).stores({
table1: "++key, AColumnName1",
table2: "++key, AColumnName2",
table3: "AColumnName3"
});
export default db;

  • in worker context:

const initialLength = scenarioPostProcess.length; // Getting the data in scenarioPostProcess
Dexie.getDatabaseNames().then((names) => {
log(Here are the names ${names});
});

new Dexie("myDB").open().then((db) => {
while (scenarioPostProcess.length) {
const bulkPutPromise = db.table1.bulkPut(scenarioPostProcess.splice(0, Math.floor(initialLength * 0.15)));
bulkPutPromise.then((lastKeyInsertInDb) => {
if (lastKeyInsertInDb) {
log(The last key inserted in table is ${lastKeyInsertInDb});
}
});
}
}).catch((error) => {
log(Issue with database: ${error});
});
Using React with JS ES6, webpack with worker-loader
Dexie 2.0.4

Any ideas would be greatly appreciated.

Most helpful comment

It's often better to declare the db instance in its own module and import the same module from both worker and web.

// db.js
import Dexie from "dexie";

export const db = new Dexie("myDB");
db.version(1).stores({
  table1: "++key, AColumnName1",
  table2: "++key, AColumnName2",
  table3: "AColumnName3"
});
// worker.js
import { db } from './db'; // You get a db with property table1 attached (because the schema is declared)

self.onmessage = event => {
  ...
  db.table1.bulkPut(...).then(lastId => {
    ...
  }).catch(error => {
    ...
  });
}

All 4 comments

Facing the same issue myself. working fine from main thread but not in worker.
I am using the worker-loader with webpack as well.

@ballabusta In the worker schenario, your example code does not specify version().stores(). That is possible, but then you need to access the tables through db.table(tableName) rather than just db.tableName as Dexie only populates the implicit table properties when in version().stores().

It's often better to declare the db instance in its own module and import the same module from both worker and web.

// db.js
import Dexie from "dexie";

export const db = new Dexie("myDB");
db.version(1).stores({
  table1: "++key, AColumnName1",
  table2: "++key, AColumnName2",
  table3: "AColumnName3"
});
// worker.js
import { db } from './db'; // You get a db with property table1 attached (because the schema is declared)

self.onmessage = event => {
  ...
  db.table1.bulkPut(...).then(lastId => {
    ...
  }).catch(error => {
    ...
  });
}

Thnx @dfahlander, the db.table('someTable') approach seems to work.
Not sure what I am doing wrong here that table fields are not getting populated.

const LATEST_VERSION = 1;

class ArchDB extends Dexie {
    eois: Dexie.Table<LDefs.IEntryEOI, string>; 
    alerts: Dexie.Table<LDefs.IEntryAlerts, string>;

    constructor(dbSuffix: string) {
        super('ArchDB_' + dbSuffix);
        // using unique id strings to prevent duplicates
        this.version(LATEST_VERSION).stores({
            eois: '&id, updated, StartTime, EndTime', // Only want index by StartTime & EndTime as rest of the filtering is done in crossfilter
            alerts: '&id, updated, opentime, closetime, acktime',
        });
    }
}

export interface IDriver {
    db: ArchDB;
    ready: boolean;
}

const driver: IDriver = {
    db: null,
    ready: false,
};


export const initDriver = (domain: string) => {
    console.log('initializing local data store for : ' + domain);

    driver.db = new ArchDB(domain);

    driver.db.open().catch(function (err) {
        console.error('Failed to open db: ' + (err.stack || err));
    }).then(() => {
        driver.ready = true;
    });
};

I am checking ready to be true before accessing the table fields.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  3Comments

Script47 picture Script47  路  3Comments

oviniciuslara picture oviniciuslara  路  4Comments

remusao picture remusao  路  3Comments

matusferko picture matusferko  路  4Comments