Justin Thomas
Justin Thomas

Reputation: 5848

Getting a Binary Field from MongoDB Driver

How do I get a binary field from an existing mongo db document?

At the MongoDB console, if I do a find for the record of choice I get this:

{_id:ObjectId("1234"),"cover_data" : BinData(2,"ozkAAP/Y/+AAEEpGSUYAAQEBAJYAlgAA/+IFpElDQ19QUk9GSUxFAAEBAAAFlGFwcGwCIAAAbW50clJHQiBYWVogB9kAAgAZAAsAGgALYWNzcEFQUEwAAAAAYXBwbAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAA ..... )

In python on our web server when we do a find with pymongo it gets that field as binary and json_pickle seems to turn it to base64 automatically and alas the image looks great when sent back to the client. When I compare the generated base64 to the node.js mongo driver it's completely different and doesn't display the image properly.

Here is the code for Node.JS:

cb = function(comp) {
    thumb_buffer = new Buffer(comp.thumbnail_data.value(),'binary');
    comp.thumbnail_data = thumb_buffer.toString('base64');
}

In the examples and test cases here: https://github.com/christkv/node-mongodb-native I don't see any example of what I'm trying to do. There seem to be BSON deserializers and a BinaryParser that is used in the case of a whole BSON object. I tried it for just the one field and got a segmentation faults.

Running list of things I've tried:

    mongo_compositions.find {_id:{$in:ids}},{},(err,compositions) -> 
            for comp in compositions
                do(comp) =>
                    thumb_buffer = comp.thumbnail_data.value(true)
                    test_buffer = Binary(thumb_buffer)
                    console.log test_buffer
                    console.log test_buffer.toString('base64')
                    #thumb_buffer = BSON.deserialize thumb_buffer
                    #thumb_buffer.write(comp.thumbnail_data.value(true))
                    #comp.thumbnail_data = thumb_buffer.toString('base64')
                    #cover_buffer = new Buffer(comp.cover_data.value(),'binary')
                    #console.log thumb_buffer.toString('base64')
                    #console.log "#{comp.composition_author} - #{comp.thumbnail_data.length}"
                    #comp.cover_data = cover_buffer.toString('base64')

Upvotes: 3

Views: 9652

Answers (2)

Justin Thomas
Justin Thomas

Reputation: 5848

As it turns out for: myDoc.binaryField.value( true ); The first 4 bytes (32-bits) are the big endian length of the size of the data. If you read from past those 4 bytes the buffer then that will end up being the data.

In my case the start of the data looked like this in hex:

63 12 00 00 ff d8 ff e0 00 10 4a 46

The python data looked like this:

ff d8 ff e0 00 10 4a 46

Binary = client.bson_serializer.Binary
binary = new Binary(myDoc.binaryField.value( true ))
buffer = new Buffer(binary.toString(),'binary')
length_buf = buffer.slice(0,4)
length = length_buf[3] << 32 | length_buf[2] << 16 | length_buf[1] << 8 | length_buf[0]
buffer.slice(4).slice(0,length).toString(enc)

Upvotes: 2

Nican
Nican

Reputation: 7935

I am a bit confused on what you are trying to do. When selecting/inserting binary elements into MongoDB using node-mongodb, you must use binary bson object.

var buffer = new Buffer(); /* your binary data */
var binary = client.bson_serializer.Binary( buffer );
var myDoc = {
    binaryField: binary;
}
//And for when selecting the document
var buffer = myDoc.binaryField.value( true ); 

Set the toString argument to true to select it as a Buffer; false to return as "binary", but as the manual says, it should be avoided towards the buffer object.

To translate from a buffer to base64:

buffer.toString('base64');

Upvotes: 4

Related Questions