Closed chumager closed 6 years ago
@chumager I will appreciate the spec to reproduce the problem you are facing.
sorry for the delay, my github mails go to a filtered place.
Let's begin... first of all you use mongoose, you should let the developer give you the connection, and use it, for everything, so when you declare a Schema or Model, they will get in the correct object.
second you use getters in the storage, so, in the meanwhile you don't ask for them, they ain't exist...
third in the schema declaration, inside methods and statics you use mongoose object, this is the standard for connections, but not the only way to connect.
I use let db = new mongoose.Mongoose();
because I connect to severan DBs... I can develop a PR if you like, either way I had to change your code to make my programs work.
After looking all your code, IMHO, will be better to return the model, and apply all the statics and methods directly to the schema. so you should pass all the storage logic into the schema, use promises instead of callbacks...
What do you think?
Regards.
Hi this is my test, to provide stream, promises and CB, I just develop the methods a needed, take a look and tell what do you think.
BTW, if you ain't like Q promises you can change them with new Promise
read-all-stream is not the most popular module, but it allows to use promises and cb and define the encode option so you can get a buffer of a string,
"use strict";
const mongoose = require("mongoose");
const fs = require("fs");
const Q = require("q");
Q.longStackSupport = true;
let db = new mongoose.Mongoose();
const Grid = require("gridfs-stream");
const read = require("read-all-stream");
db.connect("mongodb://localhost/test").then(()=>{
console.log("connected");
const bucket = "fs";
const gfs = new Grid(db.connection.db, db.mongo);
let File = new db.Schema({//Esquema base de los usuarios.
length: {
type: Number
},
chunkSize: {
type: Number
},
uploadDate: {
type: Date
},
md5: {
type: String
},
filename: {
type: String
},
contentType: {
type: String
},
metadata: {
type: Object
},
path:{
type:String,
readonly:true
}
},{collection:`${bucket}.files`});
File.path("_id").options.hidden=true;
const fixQuery = q=>{
if(q.contentType){
q.content_type = q.contetType;
delete q.contentType;
}
q.root = bucket;
return q;
};
File.method({
read(){
let query = this.toJSON({setters:false,getters:false,versionKey:false});
let res = gfs.createReadStream(fixQuery(query));
const handler = {
get(target,prop){
switch(prop){
case "then":
case "catch":
//pseudo promise;
let r = read(res,null);
return r[prop].bind(r);
case "raw":
//in case to redefine options or wanting CB
return (...args)=>read(res,...args);
default:
return Reflect.get(target,prop);
}
}
};
return new Proxy(res,handler);
},
});
File.method("remove",function remove(){
let q = {_id:this._id};
return Q.Promise((res,rej)=>{
gfs.remove(fixQuery(q),err=>{
if(err) rej(err);
res();
});
});
},{
suppressWarning: true
});
File.static({
write(file){
let self = this;
let query = fixQuery(file);
let res = gfs.createWriteStream(query);
let resolve, reject;
let p = new Promise((res,rej)=>{
resolve = res;
reject = rej;
});
res.on("error",err=>{
reject(err);
});
res.on("close",file=>{
resolve(self.findById(file._id));
});
const handler = {
get(target,prop){
switch(prop){
case "then":
case "catch":
return p[prop].bind(p);
default:
return Reflect.get(target,prop);
}
}
};
return new Proxy(res,handler);
},
remove(q){
return Q.Promise((res,rej)=>{
gfs.remove(fixQuery(q),err=>{
if(err) rej(err);
res();
});
});
},
exist(q){
return Q.Promise((res,rej)=>{
gfs.exist(fixQuery(q),(err,found)=>{
if(err) rej(err);
res(found);
});
});
},
});
//TEST!!!
db.model("File",File);
console.log("File model", db.models.File);
let file = fs.createReadStream("test.txt");
let writer = db.model("File").write({
filename:"test",
contentType:"application/octet-stream"
});
writer.then(res=>{
console.log("result",res);
db.models.File.exist(res).then(console.log,console.error);
return Q.all([
res,//to keep the data
res.read(),
//with a grapper to conver it into a promise but it's a CB anyway
new Promise(r=>{
res.read().raw(null,(err,data)=>{
r(data);
});
}),
res.read().raw(null),
]);
}).then(res=>{
console.log(res);
console.log("writing into stream");
let arch = fs.createWriteStream("test2.txt");
let reader = res[0].read();
return new Promise(resolve=>{
arch.on("close",()=>{
console.log("arch writed");
resolve(res[0]);
});
reader.pipe(arch);
});
}).then(res=>{
console.log("removing file");
return res.remove();
}).then(()=>{
console.log("file removed");
}).catch(err=>{
console.log("ERROR",err);
});
file.pipe(writer);
}).catch(console.error);
Hi everyone, I am facing the same problem when I use a separate mongoose connection. I came across this bug while I tried to write into gridfs, the callback never fires.
let conn = await mongoose.createConnection(config, { keepAlive: true });
let gridfs = require('mongoose-gridfs')({
collection: 'fs',
model: 'gridfile',
mongooseConnection: conn,
});
// .... apply plugins to gridfs.schema
let GridFile = conn.model('gridfile', gridfs.schema); // actually this line is also wrong but I can't think of how to register the model in my own `conn`, and gridfs.model is readonly
(new GridFile({
filename: 'a'
})).write(stream, (err, file) => { console.log(file); }); // cb won't fire
In which I was unaware that the underlying Grid was using my conn
to write the file while the GridFSSchema.methods.write
is using the default connection and for some reason the done
is never called at https://github.com/lykmapipo/mongoose-gridfs/blob/40d05e975c32a0bdc9626eb316504ca8db6b967f/lib/schema.js#L83
@lkho Appreciated for the trace.
Hi, AFAIK some statics and methods refers to mongoose and not the real db, in my case i've several connections with mongoose.Mongoose, and when tried to unlink or use another function referred to mongoose it throws an error.
You just have to change all mongoose for this inside all methods and statics.
regards.