Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js / MongoDB / Mongoose: Buffer Comparison

First, a little background:

I'm trying to check to see if an image's binary data has already been saved in Mongo. Given the following schema:

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);

...I want to query to see if an image exists, if it does add a reference that my object is using it, and then update it. If it doesn't, I want to create (upsert) it.

Given the case that it does not exist, the below code works perfectly. If it does, the below code does not and adds another Image document to Mongo. I feel like it is probably a comparison issue for the Mongo Buffer type vs node Buffer, but I can't figure out how to properly compare them. Please let me know how to update the below! Thanks!

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!!!
});
like image 568
guydog28 Avatar asked Mar 22 '23 11:03

guydog28


1 Answers

Mongoose converts Buffer elements destined to be stored to mongodb Binary, but it performs the appropriate casts when doing queries. The expected behavior is also checked in units tests (also the storage and retrieval of a node.js Buffer).

Are you sure you are passing a node.js Buffer?

In any case I think the best approach to handle the initial problem (check if an image is already in the db) would be storing a strong hash digest (sha1, sha256, ...) of the binary data and check that (using the crypto module). When querying, as a preliminary test you could also check the binary length to avoid unnecessary computations.

For an example of how to get the digest for your image before storing/querying it:

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');
like image 63
Marco Pantaleoni Avatar answered Mar 25 '23 02:03

Marco Pantaleoni