2

是否有内置解决方案来防止Blob不同记录中的重复对象IndexedDB

假设我有一个音乐商店的模式:id, title, album, artwork,我想将同一张专辑中的 2 首歌曲添加到该商店(因此它们很可能具有相同的艺术品资产)。是否有一种内置方法可以只自动存储一次艺术品?

我试过的:

  • 我试图unique在索引中设置一个标志artwork,但是在插入第二首歌曲(使用)之前和之后检查数据库的大小之后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对象不支持吗?

4

1 回答 1

3

尽管 IndexedDB 支持存储 Blob,但它不支持索引 Blob。可索引属性只能是字符串、数字、日期或数组类型<string | 号码 | 日期>。如果没有,IndexedDB 将默默忽略以索引该特定对象。

此外,在您的示例代码中,您没有引用艺术品表,而是尝试将 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)。但是,我绝不建议在任何数据库中索引如此大的值。最好对摘要进行索引。

于 2017-03-07T23:49:07.560 回答