realmiwi
realmiwi

Reputation: 41

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.

Upvotes: 4

Views: 2846

Answers (1)

Jordan Bachmann
Jordan Bachmann

Reputation: 61

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);
})();

Upvotes: 6

Related Questions