防止 IndexedDB 中出现重复的 Blob 对象
Preventing duplicate Blob objects in IndexedDB
是否有内置解决方案来防止 IndexedDB
中不同记录中的重复 Blob
对象?
假设我有一个音乐商店的架构:id, title, album, artwork
,我想将同一专辑中的 2 首歌曲添加到该商店(因此它们很可能具有相同的艺术品资产)。是否有内置方法可以自动仅存储一次图稿?
我试过的:
我试图在artwork
索引中设置一个unique
标志,但是在检查插入第二首歌曲前后的数据库大小(使用chrome://settings/cookies
), 作品存储两次.
然后我尝试用相同的标志将艺术品存储在单独的商店中(只有 id
和 artwork
作为架构),但是没有用也是。
var database = new Dexie('TheDatabase');
database.version(1).stores({artworks: '++id, &artwork'});
var dbArt = database.artworks;
var artworkBlob = getBlob(image);
dbArt.put(artworkBlob);
//later:
dbArt.put(artworkBlob);
我是否以任何方式滥用了 unique
标志? Blob
个对象不支持它吗?
尽管 IndexedDB 支持存储 Blob,但不支持索引 Blob。可索引属性只能是 string、number、Date 或 Array.如果不是,IndexedDB 将默默地忽略索引该特定对象。
此外,在您的示例代码中,您没有引用艺术作品 table,并且您试图单独放置 blob 而不是放置包含 blob 的文档 属性。
因此您可以改为计算 blob 内容的哈希/摘要并将其存储为字符串,您可以使用唯一索引对其进行索引。
var dbArt = new Dexie('TheDatabase');
dbArt.version(1).stores({
artworks: `
++id,
title,
album,
&artworkDigest` // & = unique index of the digest
});
var artworkBlob = getBlob(image); // get it somehow...
// Now, compute hash before trying to put blob into DB
computeHash(artworkBlob).then(artworkDigest => {
// Put the blob along with it's uniqely indexed digest
return dbArt.artworks.put({
title: theTitle,
album: theAlbum,
artwork: artworkBlob,
artworkDigest: artworkDigest
});
}).then(()=>{
console.log("Successfully stored the blob");
}).catch(error => {
// Second time you try to store the same blob, you'll
// end up here with a 'ConstraintError' since the digest
// will be same and conflict the uniqueness constraint.
console.error(`Failed to store the blob: ${error}`);
});
function computeHash (blob) {
return new Promise((resolve, reject) => {
// Convert to ArrayBuffer
var fileReader = new FileReader();
fileReader.onload = () => resolve(filerReader.result);
fileReader.onerror = () => reject(filerReader.error);
fileReader.readAsArrayBuffer(blob);
}).then (arrayBuffer => {
// Compute Digest
return crypto.subtle.digest("SHA-256", arrayBuffer);
}).then (digest => {
// Convert ArrayBuffer to string (to make it indexable)
return String.fromCharCode.apply(
null, new Uint8Array(digest));
});
};
我还建议存储 ArrayBuffer 而不是 blob(因为无论如何我们都会将 blob 读取到 ArrayBuffer 中。我的示例没有显示这一点,但您可以将 computeHash() 拆分为两个不同的函数 - 一个将 blob 读入一个 ArrayBuffer 和另一个对其进行哈希处理的数组。如果您存储 ArrayBuffer 而不是 blob,则在 Safari 和其他一些旧版本的 firefox 中将不太容易出错。
旁注:在 IndexedDB 2.0 中,ArrayBuffers 是可索引的(但 Blob 仍然不是)。但是,我绝不会建议在任何数据库中索引如此大的值。最好为摘要编制索引。
是否有内置解决方案来防止 IndexedDB
中不同记录中的重复 Blob
对象?
假设我有一个音乐商店的架构:id, title, album, artwork
,我想将同一专辑中的 2 首歌曲添加到该商店(因此它们很可能具有相同的艺术品资产)。是否有内置方法可以自动仅存储一次图稿?
我试过的:
我试图在
artwork
索引中设置一个unique
标志,但是在检查插入第二首歌曲前后的数据库大小(使用chrome://settings/cookies
), 作品存储两次.然后我尝试用相同的标志将艺术品存储在单独的商店中(只有
id
和artwork
作为架构),但是没有用也是。
var database = new Dexie('TheDatabase');
database.version(1).stores({artworks: '++id, &artwork'});
var dbArt = database.artworks;
var artworkBlob = getBlob(image);
dbArt.put(artworkBlob);
//later:
dbArt.put(artworkBlob);
我是否以任何方式滥用了 unique
标志? Blob
个对象不支持它吗?
尽管 IndexedDB 支持存储 Blob,但不支持索引 Blob。可索引属性只能是 string、number、Date 或 Array
此外,在您的示例代码中,您没有引用艺术作品 table,并且您试图单独放置 blob 而不是放置包含 blob 的文档 属性。
因此您可以改为计算 blob 内容的哈希/摘要并将其存储为字符串,您可以使用唯一索引对其进行索引。
var dbArt = new Dexie('TheDatabase');
dbArt.version(1).stores({
artworks: `
++id,
title,
album,
&artworkDigest` // & = unique index of the digest
});
var artworkBlob = getBlob(image); // get it somehow...
// Now, compute hash before trying to put blob into DB
computeHash(artworkBlob).then(artworkDigest => {
// Put the blob along with it's uniqely indexed digest
return dbArt.artworks.put({
title: theTitle,
album: theAlbum,
artwork: artworkBlob,
artworkDigest: artworkDigest
});
}).then(()=>{
console.log("Successfully stored the blob");
}).catch(error => {
// Second time you try to store the same blob, you'll
// end up here with a 'ConstraintError' since the digest
// will be same and conflict the uniqueness constraint.
console.error(`Failed to store the blob: ${error}`);
});
function computeHash (blob) {
return new Promise((resolve, reject) => {
// Convert to ArrayBuffer
var fileReader = new FileReader();
fileReader.onload = () => resolve(filerReader.result);
fileReader.onerror = () => reject(filerReader.error);
fileReader.readAsArrayBuffer(blob);
}).then (arrayBuffer => {
// Compute Digest
return crypto.subtle.digest("SHA-256", arrayBuffer);
}).then (digest => {
// Convert ArrayBuffer to string (to make it indexable)
return String.fromCharCode.apply(
null, new Uint8Array(digest));
});
};
我还建议存储 ArrayBuffer 而不是 blob(因为无论如何我们都会将 blob 读取到 ArrayBuffer 中。我的示例没有显示这一点,但您可以将 computeHash() 拆分为两个不同的函数 - 一个将 blob 读入一个 ArrayBuffer 和另一个对其进行哈希处理的数组。如果您存储 ArrayBuffer 而不是 blob,则在 Safari 和其他一些旧版本的 firefox 中将不太容易出错。
旁注:在 IndexedDB 2.0 中,ArrayBuffers 是可索引的(但 Blob 仍然不是)。但是,我绝不会建议在任何数据库中索引如此大的值。最好为摘要编制索引。