I wrote an application in Node.js that stores images in the MongoDB GridFS file system.
I uploaded the images through the app and the images look right:
$ mongofiles -v -d speaker-karaoke get howard-basement-100x115.jpg Tue Jul 17 12:14:16 creating new connection to:127.0.0.1 Tue Jul 17 12:14:16 BackgroundJob starting: ConnectBG Tue Jul 17 12:14:16 connected connection! connected to: 127.0.0.1 done write to: howard-basement-100x115.jpg
This grabbed the .jpg from MongoDB and I was able to open it without a problem, so it looks like I'm loading correctly.
However, in my running application, when I try to read the same file, I get:
12:15:44 web.1 | started with pid 89621 12:15:45 web.1 | Connecting to mongodb://localhost/speaker-karaoke 12:15:45 web.1 | Speaker Karaoke express app started on 5000 12:15:48 web.1 | DEBUG: Get review thumbnail for 5005b7550333650000000001 12:15:48 web.1 | 12:15:48 web.1 | node.js:201 12:15:48 web.1 | throw e; // process.nextTick error, or 'error' event on first tick 12:15:48 web.1 | ^ 12:15:48 web.1 | Error: Illegal chunk format 12:15:48 web.1 | at Error (unknown source) 12:15:48 web.1 | at new <anonymous> (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongodb/lib/mongodb/gridfs/chunk.js:43:11) 12:15:48 web.1 | at /Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:488:24 12:15:48 web.1 | at Cursor.nextObject (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:462:5) 12:15:48 web.1 | at [object Object].<anonymous> (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:456:12) 12:15:48 web.1 | at [object Object].g (events.js:156:14) 12:15:48 web.1 | at [object Object].emit (events.js:88:20) 12:15:48 web.1 | at Db._callHandler (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1290:25) 12:15:48 web.1 | at /Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:329:30 12:15:48 web.1 | at [object Object].parseBody (/Users/hlship/workspaces/github/speaker-karaoke/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:118:5) 12:15:48 web.1 | process terminated 12:15:48 system | sending SIGTERM to all processes
Using this code (CoffeeScript, for Express):
app.get "/images/review-thumbnail/:id", (req, res) -> id = req.params.id util.debug "Get review thumbnail for #{id}" store = new GridStore mongoose.connection.db, new ObjectID(id), null, "r" store.open (err, file) -> throw err if err util.debug "Store open for #{id}, type = #{file.contentType}"
Thus, it does not seem to even refer to the return message passed to store.open ().
Is there a problem opening a GridFS file when you know the identifier but not the file name?
BTW:
$ npm ls speaker-karaoki@0.0.1 /Users/hlship/workspaces/github/speaker-karaoke ├─┬ blueimp-file-upload-node@1.0.2 extraneous │ ├── formidable@1.0.11 │ ├── imagemagick@0.1.2 │ └── node-static@0.6.0 ├── coffee-script@1.3.3 ├─┬ connect-assets@2.1.9 │ ├── connect-file-cache@0.2.4 │ ├── mime@1.2.2 │ ├─┬ snockets@1.3.4 │ │ ├── coffee-script@1.3.3 │ │ ├── dep-graph@1.0.1 │ │ └── uglify-js@1.0.7 │ └── underscore@1.1.7 ├─┬ express@2.5.9 │ ├─┬ connect@1.9.1 │ │ └── formidable@1.0.11 │ ├── mime@1.2.4 │ ├── mkdirp@0.3.0 │ └── qs@0.4.2 ├─┬ jade@0.26.0 │ ├── commander@0.5.2 │ └── mkdirp@0.3.0 ├─┬ mongodb@1.0.2 │ └── bson@0.0.6 ├─┬ mongoose@2.7.0 │ ├── hooks@0.2.1 │ └─┬ mongodb@1.0.2 │ └── bson@0.0.6 ├─┬ passport@0.1.10 │ └── pkginfo@0.2.3 ├─┬ passport-twitter@0.1.3 │ ├─┬ passport-oauth@0.1.9 │ │ ├── oauth@0.9.7 │ │ └── passport@0.1.11 │ └── pkginfo@0.2.3 ├── sass@0.5.0 └── underscore@1.3.3
And here is the function where it does not work:
var Chunk = exports.Chunk = function(file, mongoObject) { if(!(this instanceof Chunk)) return new Chunk(file, mongoObject); this.file = file; var self = this; var mongoObjectFinal = mongoObject == null ? {} : mongoObject; this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id; this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n; this.data = new Binary(); if(mongoObjectFinal.data == null) { } else if(typeof mongoObjectFinal.data == "string") { var buffer = new Buffer(mongoObjectFinal.data.length); buffer.write(mongoObjectFinal.data, 'binary', 0); this.data = new Binary(buffer); } else if(Array.isArray(mongoObjectFinal.data)) { var buffer = new Buffer(mongoObjectFinal.data.length); buffer.write(mongoObjectFinal.data.join(''), 'binary', 0); this.data = new Binary(buffer); } else if(mongoObjectFinal.data instanceof Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") { this.data = mongoObjectFinal.data; } else if(Buffer.isBuffer(mongoObjectFinal.data)) { } else { throw Error("Illegal chunk format"); }
Decision
The solution update is here, as it does not display correctly in the comments below.
The problem was duplication; having two copies, even with the same version, from mongodb and bson.
Fortunately, mongoose exports mongodb, which is required as a mongo property, so I managed to remove the explicit mongodb from my package.json
and change:
mongo = require "mongodb" mongoose = require "mongoose"
in
mongoose = require "mongoose" mongo = mongoose.mongo
Now everything looks good; I still think that a modular system needs an authorized way to access dependency dependencies (for the case when the folder is not thoughtful enough to expose its fingerprints).