Deprecation errors in mongoDB, where should I pass the parameters? - node.js

I'm using mongoDB to store 2 files, and I get those messages:
DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to
the MongoClient constructor.
this is my code, I have no idea where should I pass those options to:
var storageImage = new GridFsStorage({
url: dbURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "user_images"
};
resolve(fileInfo);
});
});
}
});
const uploadImage = multer({ storage: storageImage });
var storageDoc = new GridFsStorage({
url: dbURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "user_cv"
};
resolve(fileInfo);
});
});
}
});
const uploadDoc = multer({ storage: storageDoc });
//routes
router.post("/uploadImage", uploadImage.single("file"), (req, res) => {
console.log(req.file);
res.json({ imageId: req.file.id });
});
router.post("/uploadCV", uploadDoc.single("file"), (req, res) => {
console.log(req.file);
res.json({ cvId: req.file.id });
});
module.exports = router;

Try like this. Adding this line should work options: { useNewUrlParser: true }.
new GridFsStorage({
url: dbURI,
options: { useNewUrlParser: true },
...,
});

Related

Multer typescript error next(err) is not a function

I am developing a MEAN stack app for photo upload and I'm encountering an issue with the follow error. Currently testing this endpoint with postman, everytime I upload an image to the folder the server will stop running and I recieve this error. Any help would be appreciated
node_modules\multer\lib\make-middleware.js:45make-middleware.js:45
next(err)
^
TypeError: next is not a function
In my post.controller.js
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now() + '-' + getExtension(file));
},
});
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
});
const getExtension = (file) => {
// this function gets the filename extension by determining mimetype. To be exanded to support others, for example .jpeg or .tiff
var res = '';
if (file.mimetype === 'image/jpeg') res = '.jpg';
if (file.mimetype === 'image/png') res = '.png';
return res;
};
(exports.create = upload.single('imagePath')),
async (req, res, next) => {
try {
console.log(req.file, req.body);
const { title, date } = req.body;
const imagePath = req.file.path;
const post = new Posts({
title,
date,
imagePath,
});
await post.save();
return res.status(200).json({
success: true,
post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: 'Server Error',
error: error,
});
}
};
And my posts.route.js
const express = require('express');
const PostsController = require('../controllers/posts.controller');
const Auth = require('../auth/auth');
const multer = require('multer');
const route = express.Router();
route.post('/create', Auth.authenticateJWT, (req, res) => {
PostsController.create(req, res);
});
route.get('/', Auth.authenticateJWT, (req, res) => {
PostsController.getAllPosts(req, res);
});
route.get('/:id', Auth.authenticateJWT, (req, res) => {
PostsController.getPost(req, res);
});
module.exports = route;
You should define create as:
exports.create = async (req, res, next) => {
try {
console.log(req.file, req.body);
const { title, date } = req.body;
const imagePath = req.file.path;
const post = new Posts({
title,
date,
imagePath,
});
await post.save();
return res.status(200).json({
success: true,
post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: 'Server Error',
error: error,
});
}
};
Export the upload variable:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now() + '-' + getExtension(file));
},
});
exports.upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
});
And use it as a middleware:
route.post('/create', Auth.authenticateJWT, PostsController.upload('imagePath'), PostsController.create);

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'unlink' of undefined at Grid.remove

I'm trying to delete a file by its id using gridfs but I get this error when calling the delete API.
Controller :
let gfs;
connect.once("open", () => {
gfs = Grid(connect.db, mongoose.mongo);
gfs.collection("uploads");
});
exports.deleteFile = (req, res) => {
try {
gfs.remove(
{ _id: req.params.id, root: "uploads" },
(err, gridStore) => {
if (err) {
return res.status(404).send({ message: err });
} else {
return res.send({ message: "File deleted successfuly" });
}
}
);
} catch (error) {
return res.status(500).send({
message: error.message,
});
}
};
exports.deleteFileByFilename = async (req, res, next) => {
const file = await gfs.files.findOne({ filename: req.params.filename });
const gsfb = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' });
gsfb.delete(file._id, function (err, gridStore) {
if (err) return next(err);
res.status(200).end();
});
};
// #route DELETE /files/:filename
// #desc Delete file
app.delete('/files/:filename', async (req, res) => {
const file = await gfs.files.findOne({ filename: req.params.filename });
const gsfb = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' });
gsfb.delete(file._id, function (err, gridStore) {
if (err) {
res.status(404).send('no file found')
}
res.status(200).send('deleted successfully')
});
});
On client side:
const delImage = async (fileName) => {
await axios.delete(`http://localhost:5000/files/${fileName}`);
console.log('fileDeleted');
getData(); // reminder to REFETCH the data so that database with deleted file is refreshed
}
I also made a video on this - full file uploads, multiupload, display and delete using MERN stack and NPM Multer thing, in here: https://youtu.be/4WT5nvfXcbs
Docs for the video with full code: https://docs.google.com/document/d/1MxvNNc9WdJT54TpanpFBT6o7WE_7hPAmDhdRNWE8A9k/edit?usp=sharing

How can I delete a file with multer gridfs storage?

The following code works as expected to upload and retrieve files:
// Mongo URI
const mongoURI = 'mongodbconnstring';
// // Create mongo connection
const conn = mongoose.createConnection(mongoURI);
// // Init gfs
let gfs;
conn.once('open', () => {
gfs = new mongoose.mongo.GridFSBucket(conn.db, {
bucketName: 'Uploads'
});
});
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
const filename = file.originalname; //+ Date.now();
const fileInfo = {
filename: filename,
bucketName: 'Uploads'
};
resolve(fileInfo);
});
}
});
const upload = multer({ storage });
// // #route POST /upload
// // #desc Uploads file to DB
routerUpload.post('/upload', upload.single('files'), (req, res) => {
//res.json({file: req.file})
res.redirect('/');
});
// #route GET /files
// #desc Display all files in json
routerUpload.get('/files', (req, res) => {
gfs.find().toArray((err, files) => {
// Check if files
if (!files || files.length === 0) {
return res.status(404).json({
err: 'No files exist'
});
}
return res.json(files);
});
});
// #route GET /files/:filename
// #desc Display single file object
routerUpload.get('/files/:filename', (req, res) => {
const file = gfs
.find({
filename: req.params.filename
})
.toArray((err, files) => {
if (!files || files.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
gfs.openDownloadStreamByName(req.params.filename).pipe(res);
});
});
However, when I call the code below to delete the file by ID:
// #route DELETE /files/:id
// #desc Delete file
routerUpload.post('/files/del/:id', (req, res) => {
gfs.delete(req.params.id, (err, data) => {
if (err) {
return res.status(404).json({ err: err.message });
}
res.redirect('/');
});
});
I get this error in Postman:
{
"err": "FileNotFound: no file with id 5db097dae62a27455c3ab743 found"
}
Can anyone point me in the direction of where I need to go with this? I tried with the delete method instead of post, and even specified the root of the file, but the same error occurs. Thanks!
Have you tried this
// #route DELETE /files/:id
// #desc Delete file
routerUpload.post('/files/del/:id', (req, res) => {
gfs.remove({ _id: req.params.id, root: "uploads" }, (err, gridStore) => {
if (err) {
return res.status(404).json({ err });
}
return;
});
});
However I'm using an old version of express hence receiving this
(node:6024) DeprecationWarning: collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.
and
(node:6024) DeprecationWarning: Mongoose: findOneAndUpdate() and findOneAndDelete() without the useFindAndModify option set to false are deprecated
this is due to the version of express, multer and GridFs that I'm using
express: ^4.17.1
multer: ^1.4.2"
multer-gridfs-storage: ^3.3.0

Data not saving to mongodb

I'm currently trying upload images to a database by using Mutler and GridFS - which is successful. But I'm also trying to create a caption via the same form, but saving the data into a different schema. My problem is that on the POST route, it's not saving the data to the Posts schema - but no errors are being returned - but as well as that, I'm not being redirected the index page.
model.js schema for caption data
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
caption: {
type: String,
},
fileID: {
type: mongoose.Schema.Types.ObjectId,
ref: 'fs' //created by multer gridfs storage
}
});
const Posts = mongoose.model('Posts', PostSchema);
module.exports = { Posts };
app.js
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
app.use(methodOverride("_method"));
app.set("view engine", "ejs");
// Mongo URI
const mongoURI = "mongodb://localhost:27017/grid-fs";
// Mongo connection
const connection = mongoose.createConnection(mongoURI, { useNewUrlParser: true });
// Mongoose Schema
const { Posts } = require('./models/model');
// Init gfs
let gfs;
connection.once("open", () => {
// Init stream
gfs = Grid(connection.db, mongoose.mongo);
gfs.collection("uploads");
})
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "uploads"
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
app.get("/", (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files exist
if (!files || files.length === 0) {
res.render("index", {files: false})
} else {
files.map(file => {
if(file.contentType === "image/jpeg" || file.contentType === "image/png") {
file.isImage = true;
} else {
file.isImate = false;
}
});
res.render('index', {files: files})
}
});
})
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file)
const post = new Posts({
caption: req.body.caption,
fileID: req.file.id
});
console.log(req.body.caption)
console.log(req.file.id)
console.log(post)
post.save().then( result => {
res.redirect('/');
}).catch(err => {
res.status(400).send("Unable to save data");
});
});
I refresh the page the image is pushed to the frontend, but when I check the database the caption content is missing - no schema is there:
try this db.getCollectionNames() and check if your collection is there or not if it doesnot exists
try this
Posts.create({
caption: req.body.caption,
fileID: req.file.id
}, (err, data) => {
if (err) res.status(400).send("Unable to save");
else {
res.redirect("/")
}
})

404 Not found when upload files nodejs

I am using multer package
I have two ways of uploading images to my server one is with Array and the other is using fields.
The only thing that works is the uploadArray for the /status route.. when i'm uploading to /update it gives me this error SyntaxError: Unexpected token < in JSON at position 0.. The controller for the /update is just the same as the postController.js the only difference it that i update fields instead of save new one.
/utils/lib/account.js
const storage = multer.memoryStorage();
// These two image might be available in the req.files depending on what was sent
const upload = multer({storage}).fields([{ name: 'photo', maxCount: 1 }, { name: 'cover', maxCount: 1 }]);
const uploadArray = multer({storage}).array('image', 12);
exports.upload = (req, res, next) => {
upload(req, res, function (err) {
if (err) {
console.log(err);
}
next();
});
};
exports.uploadArray = (req, res, next) => {
uploadArray(req, res, function (err) {
if(err){
console.log(err);
}
next();
});
};
/routes.js
router.route('/status')
.all(helper.verifyToken)
.all(helper.uploadArray)
.get(status.get)
.post(status.new) // file uploads
.delete(status.delete);
router.route('/update')
.all(helper.verifyToken)
.all(helper.upload)
.post(account.update_profile) // file uploads
The only thing that works here is the uploadArray
/postController.js
new:
(req, res) => {
const uri = new DataUri();
const promises = [];
const images = [];
//Get buffer from files
for(let key in req.files){
const obj = req.files[key];
uri.format('.png', obj.buffer);
let uriContent = uri.content;
promises.push(uploadAsync(uriContent)); //upload each image
}
//Init upload
function uploadAsync(buffer){
return new Promise((resolve, reject) => {
cloudinary.v2.uploader.upload(buffer, function(error, result) {
if(error){
reject(error);
}
if(result.url){
images.push(result.url);
resolve(images);
}
});
});
}
Promise.all(promises)
.then(results => {
// Init post model
console.log('test1')
const post = new Post({
post_img: images,
post_description: req.body.description,
post_by: req.body.id,
photoURL: req.body.id,
post_comments: []
});
// Save data
post.save(function(err) {
if(err) {
res.send(err);
}
var leanObject = post.toObject(); // Transform instance to plain JS Object for modification
// Modifications
leanObject['post_by'] = {
_id: leanObject['post_by'],
display_name: req.body.user, // Add current user display name
photo_url: req.body.user_photo
};
res.json({message: 'Success', type: 'success', code: 200, data: leanObject});
});
})
.catch(err => {
console.log(err);
});
},

Resources