Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compound primary keys with Dexie.js (IndexedDB) as in SQL?

How can I create a compound key (primary key) which consists of several values, for example 'id' and 'date'?

For example with SQL:

PRIMARY KEY (name, date)

So far I have always created a separate, actually useless, primary key (typescript):

export class Database extends Dexie {
item: Dexie.Table<IItem, number>;

constructor() {
    super('db');
    this.version(1).stores({
        items: '++id, name, date, description, value'
    });

    this.items = this.table('items');
    }
}

Thanks a lot for your time.

like image 283
realmiwi Avatar asked Aug 31 '25 20:08

realmiwi


1 Answers

According to the documentation, you can define a compound primary key for tables using the same square bracket syntax you'd use for defining compound keys for an index:

db.version(1).stores({
  items: '[name+date]'
});

This will result in an IndexedDB table with Key (Key path: ["name", "date"])


The Dexie TypeScript definition of the Table interface types the Key generic as any:

interface Table<T=any,Key=any> extends _Table<T,Key> {}

Allowing you to pass an array of types in as the Key for your Table declaration:

Dexie.Table<IItem, [string, Date]>;

You can query on the compound PK by passing your name and date as an array of values to the get function in the same order used to define the compound PK, [name+date]:

db.items.get([anItemName, aDate])

Below is a working example.

For reference, the IndexedDB key path that the example is matching against looks like this:

["widget", Sat Dec 12 2020 09:00:00 GMT-0500 (Eastern Standard Time)]

and the resulting console log looks like this:

{name: "widget", date: "2020-12-12T14:00:00.000Z", description: "widget_2", value: 20}

import Dexie from "dexie";

interface IItem {
  name?: string;
  date?: Date;
  description?: string;
  value?: number;
}

class ItemDatabase extends Dexie {
  items: Dexie.Table<IItem, [string, Date]>; // <<<

  constructor() {
    super("SO_64210806");
    this.version(1).stores({
      items: "[name+date]" // <<<
    });
  }
}

(async () => {
  const db = new ItemDatabase();

  await db.items.bulkPut([
    {
      name: "widget",
      date: new Date("2020-12-11T13:00:00.000Z"),
      description: "widget_1",
      value: 10
    },
    {
      name: "widget",
      date: new Date("2020-12-12T14:00:00.000Z"),
      description: "widget_2",
      value: 20
    }
  ]);

  const w2 = await db.items.get(["widget", new Date("2020-12-12T14:00:00.000Z")]); // <<<

  console.log(w2);
})();
like image 126
Jordan Bachmann Avatar answered Sep 03 '25 17:09

Jordan Bachmann