【问题标题】:Preventing duplicate Blob objects in IndexedDB防止 IndexedDB 中出现重复的 Blob 对象
【发布时间】:2017-07-28 07:43:17
【问题描述】:

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

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

我的尝试:

  • 我尝试在artwork索引中设置unique标志,但是在检查插入第二首歌曲前后的数据库大小(使用chrome://settings/cookies)后,艺术品被存储了两次.

  • 然后我尝试将艺术品存储在具有相同标志的单独存储中(只有 idartwork 作为架构),但这也没有用。

    李>

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 对象不支持吗?

【问题讨论】:

    标签: javascript google-chrome indexeddb dexie


    【解决方案1】:

    尽管 IndexedDB 支持存储 Blob,但它不支持索引 Blob。可索引属性只能是字符串、数字、日期或数组类型。如果没有,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)。但是,我绝不建议在任何数据库中索引如此大的值。最好为摘要编制索引。

    【讨论】:

    • 我实际上确实实现了一种将艺术品存储在单独商店中的散列方法(使用SparkMD5),但后来我想也许我不需要它,采取IndexedDB 索引和唯一约束的优势。不过没想到Blobs 可能不受支持。
    • 是的,关于我的示例代码,这是一个代码传输错误。固定。
    • 感谢您周到的回答。我会按照您的建议存储ArrayBuffers 而不是Blobs。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2017-12-17
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多