I have these objects, each with a 'tags' array:
bookmarks: [
{ url: '...', tags: ['news', 'fun', 'programming'] },
{ url: '...', tags: ['news'] },
{ url: '...', tags: ['fun', 'cooking'] },
{ url: '...', tags: ['hobby', 'fun'] }
]
DB:
const db = new Dexie("bookmarksdb");
db.version(1).stores({
bookmarks: 'url, *tags'
});
What would be the best (and most performant) way to receive an array (or set) containing all tags:
['news', 'fun', 'programming', 'cooking', 'hobby']
(is there a way to get all values of the 'tags' index itself?)
Edit: To display a 'tag-cloud' with numbers, I need to read all tags from the bookmarks table. So, I don't need the bookmark objects themselves, only their 'tags' arrays.
I would suggest to use index to filter out all bookmarks containing at least one of the tags and then filter out from that manually:
const tagsToRequire = ['news', 'fun', 'programming', 'cooking', 'hobby'];
const bookmarksWithFirstTag = await db.bookmarks
.where({tags: tagsToRequire[0]})
.toArray();
const bookmarkWithAllTags = bookmarkWithFirstTag.filter(bookmark => tagsToRequire.every(tag => bookmark.tags.includes(tag));
You could also utilize the index for all tags but it's not certain you would get better performance though as it will need more number of DB requests. On the other hand, in the case that the first index is very commonly used and the objects are large, this second example could maybe do better in performance:
const tagsToRequire = ['news', 'fun', 'programming', 'cooking', 'hobby'];
const keys = await Promise.all(tagsToRequire.map(tag =>
db.bookmarks.where({tags: tag}).primaryKeys()));
const intersectedKeys = keys.reduce((prev, curr) => prev.filter(key => curr.includes(key)));
const bookmarkWithAllTags = await db.bookmark.bulkGet(intersectedKeys);
This 2nd sample also requires Dexie version 3.x that has the bulkGet() operation.