J'ai écrit une application en Node.js qui stocke des images dans le système de fichiers GridFS de MongoDB.
J'ai téléchargé des images via l'application, et les images semblent être stockées correctement :
$ 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
Le fichier .jpg a été extrait de MongoDB et j'ai pu l'ouvrir sans problème. Il semble donc que ce que je télécharge soit stocké correctement.
Cependant, dans mon application en cours d'exécution, lorsque je tente de lire le même fichier, j'obtiens :
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
En utilisant ce code (CoffeeScript, pour 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}"
# TODO: Scale the image before sending it!
res.header "Content-Type", file.contentType
store.stream(true).pipe res
Il semble donc qu'il n'arrive même pas jusqu'au rappel passé à store.open().
Y a-t-il un problème pour ouvrir un fichier GridFS lorsque vous connaissez l'identifiant, mais pas le nom du fichier ?
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
Et voici la fonction où il échoue :
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");
}
// Update position
this.internalPosition = 0;
};
Solution
Mise à jour de la solution ici car elle ne s'affiche pas correctement dans les commentaires ci-dessous.
Le problème était la duplication ; avoir deux copies, même avec la même version, de mongodb et bson.
Heureusement, mongoose exporte le mongodb dont il a besoin en tant que propriété mongo, ce qui m'a permis de supprimer le mongodb explicite de ma page d'accueil. package.json
et changé :
mongo = require "mongodb"
mongoose = require "mongoose"
à :
mongoose = require "mongoose"
mongo = mongoose.mongo
Les choses ont maintenant l'air bien ; je pense toujours que le système de modules a besoin d'une manière sanctionnée d'accéder aux dépendances d'une dépendance (pour le cas où une dépendance n'est pas assez réfléchie pour exposer ses dépendances).