【问题标题】:Node.js / MongoDB / Mongoose: Buffer ComparisonNode.js / MongoDB / Mongoose:缓冲区比较
【发布时间】:2013-12-26 18:36:54
【问题描述】:

首先,一点背景:

我正在尝试检查图像的二进制数据是否已保存在 Mongo 中。给定以下架构:

var mongoose = require('mongoose')
  , Schema = mongoose.Schema;

var imageSchema = new Schema({
    mime:  String,
    bin: { type: Buffer, index: { unique: true }},
    uses : [{type: Schema.Types.ObjectId}]
});

module.exports = mongoose.model('Image', imageSchema);

...我想查询图像是否存在,是否添加了我的对象正在使用它的引用,然后更新它。如果没有,我想创建(更新插入)它。

考虑到它不存在的情况,下面的代码可以完美运行。如果是,则下面的代码不会,并将另一个 Image 文档添加到 Mongo。我觉得这可能是 Mongo Buffer 类型与节点 Buffer 的比较问题,但我不知道如何正确比较它们。请让我知道如何更新以下内容!谢谢!

Image.findOneAndUpdate({
    mime : contentType,
    bin : image
}, {
    $pushAll : {
        uses : [ myObject._id ]
    }
}, {
    upsert : true
}, function(err, image) {
    if (err)
        console.log(err);
    // !!!image is created always, never updated!!!
});

【问题讨论】:

  • 你是什么时候添加唯一索引的?我花了很长时间试图弄清楚为什么它允许重复,重新启动 mongo 和重新索引在添加唯一索引后为我解决了这个问题。
  • 我在模式中设置了唯一索引,我从一开始就想。但有可能我是在创建初始集合后添加的。

标签: javascript node.js mongodb mongoose buffer


【解决方案1】:

Mongoose 将要存储的 Buffer 元素转换为 mongodb Binary,但它在执行查询时会执行适当的强制转换。 在units tests 中也检查了预期的行为(也是 node.js 缓冲区的存储和检索)。

您确定要传递 node.js 缓冲区吗?

无论如何,我认为处理初始问题(检查图像是否已经在数据库中)的最佳方法是存储二进制数据的强哈希摘要(sha1,sha256,...)并检查(使用加密模块)。 在查询时,作为初步测试,您还可以检查二进制长度以避免不必要的计算。

有关如何在存储/查询图像之前获取图像摘要的示例:

var crypto = require('crypto');

...

// be sure image is a node.js Buffer
var image_digest = crypto.createHash('sha256');
image_digest.update(image);
image_digest = image_digest.digest('base64');

【讨论】:

  • 谢谢。哈希效果很好,不敢相信我没有想到这一点。我将不得不根据您为我自己的启发而提供的那些单元测试进行一些测试。谢谢!
【解决方案2】:

通过包含图像数据的 node.js 缓冲区查询您的图像不是一个好主意。您说得对,这可能是 BSON 二进制数据类型和节点 Buffer 之间的问题,但您的应用程序真的需要这样的比较吗?

相反,我会在您的架构中添加一个 imageID 或 slug 字段,向该字段添加一个索引,然后在您的 findOneAndUpdate 调用中查询它而不是 bin

var imageSchema = new Schema({
    imageID: { type: String, index: { unique: true }},
    mime:  String,
    bin: Buffer,
    uses : [{type: Schema.Types.ObjectId}]
});

【讨论】:

  • 那么如果我想保证同一张图片不能被上传两次,即使是不同的文件名,我可以使用这种方法吗?
  • 如果您确实没有任何可用于唯一标识图像的元数据,那么您必须以某种方式比较实际的图像数据。但这只有在所有图像都具有相同格式的情况下才有效。此外,您可能需要一些更特殊用途的工具(即不是 MongoDB)来进行此类比较,一种了解图像格式并且可能无需实际逐字节比较整个图像即可进行比较的工具。
  • 散列,这就是我想要的。您的回答仍然有效且有帮助,因此 +1,但另一个正是我所需要的。谢谢。
【解决方案3】:

哈希确实有效,我使用的另一个过滤器是图像的 exif 数据。 由于这是结构化信息,如果您在 exif 数据上有匹配项,则可以进入下一步检查哈希或文件大小的匹配项...

大量节点模块,可轻松轻松地为您的存储获取 exif 数据 :) 获取节点exif数据的示例代码

【讨论】:

    猜你喜欢
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    相关资源
    最近更新 更多