Dexie.js icon indicating copy to clipboard operation
Dexie.js copied to clipboard

Dexie returns duplicated object after manually deleting the database and re-populate it.

Open laukaichung opened this issue 1 year ago • 2 comments

From: https://stackoverflow.com/questions/78618896/dexie-returns-duplicated-object-after-manually-deleting-the-database-and-re-popu

After deleting Dexie database manually, if you do not refresh the page, it will return duplicated data, even though the chrome inspector shows there are no duplicated rows in the IndexedDB. However, the issue goes away when you refresh the page right away after each database deletion.

Example: https://codesandbox.io/p/sandbox/dexie-issue-forked-djwxz6?file=%2Fsrc%2Findex.tsx

db config:

import Dexie, { EntityTable, Table } from "dexie";

const VERSION = 4.1;

export class MySubClassedDexie extends Dexie {
  playlists!: EntityTable<Playlist, "id">;

  constructor() {
    super("myDatabase");
    this.version(VERSION).stores({
      playlists: "++id,*competitionIds",
    });
  }
}

export const db = new MySubClassedDexie();

export const defaultPlaylists: Playlist[] = [
  {
    id: 1,
    competitionIds: [3, 4],
    title: "The Trial",
  },
  {
    id: 2,
    competitionIds: [1, 2],
    title: "Confederations Cup",
  },
];

db.on("populate", async () => {
  await db.playlists.bulkAdd(defaultPlaylists);
});

export interface Playlist {
  competitionIds: CompetitionId[];
  title: string;
  id: number;
}

laukaichung avatar Jun 14 '24 06:06 laukaichung

Perfect bug report, thanks!

dfahlander avatar Jun 14 '24 07:06 dfahlander

Bug is in the liveQuery cache. To workaround (until we've fixed it), disable the cache (liveQueries still work):

const db = new Dexie('dbName', { cache: 'disabled' });

dfahlander avatar Jun 18 '24 05:06 dfahlander

Bug is in the liveQuery cache. To workaround (until we've fixed it), disable the cache (liveQueries still work):

const db = new Dexie('dbName', { cache: 'disabled' });

Thanks for the update. Is this issue supposed to be fixed in v4.08?

I just updated the code at https://codesandbox.io/p/sandbox/dexie-issue-forked-2qtcl4?file=%2Fsrc%2Fdexie-db.tsx%3A9%2C23

I assume that since the database is empty in the populate event so now I use bulkAdd() instead of bulkPut(), but useLiveQuery() still keeps the default data and keeps adding up on each population.

This is the code I use for populating data again after delete():

export class MySubClassedDexie extends Dexie {
  playlists!: EntityTable<Playlist, "id">;

  constructor() {
    super("myDatabase");
    this.version(4.4).stores({
      playlists: "id",
    });

    this.on("populate", async () => {
      await db.playlists.bulkAdd([...defaultPlaylists]);
    });
  }
}

laukaichung avatar Jul 11 '24 05:07 laukaichung

Thanks for finding. This issue was due to another cause, explained in #2040.

dfahlander avatar Jul 17 '24 10:07 dfahlander

I just want to post it here for people who may encounter this issue:

Example code: https://codesandbox.io/p/sandbox/dexie-issue-forked-djwxz6

I'm not able to re-create this elusive issue with code sandbox, but on my production site, with a collection using a compound index as the primary index:

export class MySubClassedDexie extends Dexie {
  skills!: Table<Skill>;
  constructor() {
    super("myDatabase");
    this.version(13)
      .stores({
        skills: "[year+teamId],teamId",
      })
  }
}

export interface Skill {
  year: number;
  teamId: number;
  rating: number;
  text: string;
}

After you run bulkUpdate(), if you (inappropriately?) use :

  const strength2 = useLiveQuery(() => {
    return db.strengths.where("[year+teamId]").equals([year, teamId]).first();
  }, [year, teamId]);

It would show the outdated data.

You have to use get() so that the data is not dated:

  const strength = useLiveQuery(() => {
    return db.strengths.get([year, teamId]);
  }, [year, teamId]);

Again, I can't recreate it in code sandbox but using where().equal().first() may serve outdated data in my specific case. Disabling cache would solve this issue (not ideal?).

laukaichung avatar Sep 03 '24 05:09 laukaichung

Again, I can't recreate it in code sandbox but using where().equal().first() may serve outdated data in my specific case. Disabling cache would solve this issue (not ideal?).

Curious on whether you experience a single render on outdated data that immediately is being replaced with updated data, or whether the outdated data stays? Since cache: 'disabled' solves it, this is definitely something cache related. It's a pity you cannot reproduce it outside your application - it would have been great to get a repro of this.

dfahlander avatar Sep 03 '24 07:09 dfahlander

Again, I can't recreate it in code sandbox but using where().equal().first() may serve outdated data in my specific case. Disabling cache would solve this issue (not ideal?).

Curious on whether you experience a single render on outdated data that immediately is being replaced with updated data, or whether the outdated data stays? Since cache: 'disabled' solves it, this is definitely something cache related. It's a pity you cannot reproduce it outside your application - it would have been great to get a repro of this.

The outdated data stays. Either reload the page, disable caching or use get() to fix it. The stored data in IndexedDB has no problems at all. It's just the useLiveQuery(()=> db.where().equals().first()). I'll keep you posted when I can re-create it in code sandbox.

laukaichung avatar Sep 03 '24 07:09 laukaichung