UnhandledPromiseRejectionWarning: ObjectParameterError: Parameter "obj" to Document() must be an object - javascript

I am trying to upload a file and save it to a mongoose database. however, i keep getting an error
this is the error
this is the code i am using
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const uuid = require('uuid').v4;
const FileSchema = require('../models/files');
const crypto = require('crypto');
//Set Storage Engine
const storage = multer.diskStorage({
destination: (req, response, callback) => {
callback(null, './public/uploads/');
},
filename: (request, file, callback) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (error, buf) => {
if(error){
return reject(error);
}
const ext = path.extname(file.originalname);
const id = uuid();
const filePath = `files/${id}${ext}`;
FileSchema.create(filePath)
.then(() => {
callback(null, filePath);
});
});
});
}
});
//init upload
const upload = multer({storage: storage});
router.post('/uploads', upload.array('files'),(req, response) => {
return response.json({ status: 'OK', uploaded: req.files.length});
});
module.exports = router;
please can anyone help?
thank you.

Related

File upload makes Node JS unresponsive with Multer

I am using Multer Node JS package to upload files to my app sever , the code is basically typical upload file code
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
But each time a file is being uploaded the Node server becomes unresponsive and frontend from other request doesnt receive any response from other APIs until the file is uploaded.
Whats the best way to tackle this ?
In your sample code, you must just send a response to the client by res.json() or res.end() :
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
res.status(204).end();
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
res.status(204).end();
});
i can give you an example of how i implemented an imageupload in my app. it the code to upload a profile image for a user. i am also using multer middleware so it shoulder be similiar for you:
code is as follows:
// multer middleware:
const multer = require('multer');
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
};
module.exports = storage = multer.diskStorage({
destination: (req, file, cb) => {
const isValid = MIME_TYPE_MAP[file.mimetype];
let error = new Error('invalid mime type');
if (isValid) {
error = null;
}
cb(error, 'images');
},
filename: (req, file, cb) => {
const name = file.originalname.toLowerCase().split(' ').join('-');
const ext = MIME_TYPE_MAP[file.mimetype];
if (name.includes('.' + ext)) {
cb(null, name)
} else {
cb(null, name + '.' + ext);
}
},
});
and here the code in the service handling the fileupload
// profile service in backend written in express
exports.uploadImage = (req, res, next) => {
const url = req.protocol + '://' + req.get('host');
profileRepository
.findOne({ _id: req.params.id })
.then((response) => {
const fetchedUser = response;
fetchedUser.imagePath = url + '/images/' + req.file.filename;
profileRepository
.updateOne({ _id: req.params.id }, fetchedUser)
.then((response) => {
return res.status(200).json({
message: 'profileimage updated',
});
})
.catch((error) => {
return res.status(500).json({
message: 'uploading image failed',
});
});
})
.catch((error) => {
return res.status(404).json({
message: 'fetching user failed',
});
});
};
then i use the middleware in my profile routes file like this:
// profile.routes.js
const express = require('express');
const ProfileController = require('./profileController');
const checkAuth = require('../middleware/checkAuth');
const router = express.Router();
const fileStorage = require('../middleware/fileStorage');
const multer = require('multer');
// imageUpload
router.post('/user/image/:id', checkAuth, multer({storage: fileStorage}).single('image'), ProfileController.image);
my Controller then calls the service function with the actual business logic like this:
// profile.controller.js
const profileService = require('./profileService');
exports.image = (req, res, next) => {
return profileService.uploadImage(req, res);
};
and finally my route is used by my app.js file like this:
// app.js
const express = require('express');
const profileRoutes = require('./profile/profileRoutes');
const app = express();
// set images path for saving images on server
app.use('/images', express.static(path.join('images')));
app.use('/api', profileRoutes);
module.exports = app;
i hope i was able to point you in the right direction with my example

how to fix Error with Nodejs and 'gridfs-stream'

I am trying to follow along a tutorial and use nodejs with 'gridfs-stream' along with a react front end. The tutorial is from last year in 2020.
Here is my code.
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors')
const multer = require('multer');
const {GridFsStorage} = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');
const path = require('path');
const Pusher = require('pusher')
const mongoPosts = require ('./mongoPosts.js')
// const currentTournamentControllers = require('../controllers/currenttournament-controllers');
const app = express();
const port = process.env.PORT || 9000
app.use(bodyParser.json())
app.use(cors())
const mongoURI = 'mongodb+srv://fbclient:rmbmbkvZVHw3e6OK#cluster0.emaw1.mongodb.net/myFirstDatabase?retryWrites=true&w=majority'
const conn = mongoose.createConnection(mongoURI);
mongoose.connect(mongoURI)
mongoose.connection.once('open', () => {
console.log('DB Connected')
})
let gfs
conn.once('open', () => {
// Init stream
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('images');
});
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {{
const filename = `image-${Date.now()}${path.extname(file.originalname)}`
const fileInfo = {
filename: filename,
bucketName: 'images'
}
resolve (fileInfo)
}})
}
})
const upload = multer({storage})
app.get('/', (req, res) => res.status(200).send('hello world'))
app.post('/upload/image', upload.single('file'), (req, res) => {
res.status(201).send(req.file)
})
app.post('/upload/post', (req, res) => {
const dbPost = req.body
console.log(dbPost)
mongoPosts.create(dbPost, (err, data) => {
if(err){
res.status(500).send(err)
} else {
res.status(201).send(data)
}
})
})
app.get('/retrieve/image/single', (req, res) => {
console.log(req.query.name)
gfs.files.findOne({filename: req.query.name}, (err, file) => {
if(err) {
res.status(500).send(err)
} else {
console.log(file)
if(!file || file.length === 0) {
console.log("hi i errored out")
res.status(404).json({err: 'file not found'})
} else {
console.log("hi i am trying to read")
const readstream = gfs.createReadStream(file.filename)
readstream.pipe(res)
}
}
})
})
app.get('/retrieve/posts', (req, res) => {
mongoPosts.find((err, data) => {
if(err){
res.status(500).send(err)
} else {
data.sort((b,a) => {
return a.timestamp - b.timestamp
})
res.status(200).send(data)
}
})
})
app.listen(port, () => console.log(`listening on localhost:${port}`))
The problem is with readstream. When I am trying to retrieve the data it shows the error
TypeError: grid.mongo.ObjectID is not a constructor
I did some debugging and figured out that this can be fixed by changing a value inside the gridfs.js file in the node_modules. The change being suggested on Stack Overflow was this :-
this._store = new grid.mongo.GridStore(grid.db, this.id || new grid.mongo.ObjectID(), this.name, this.mode, options);
changed to
this._store = new grid.mongo.GridStore(grid.db, this.id || new grid.mongo.ObjectId(), this.name, this.mode, options);
The suggestion was to change the grid.mongo.ObjectID value to grid.mongo.ObjectId. So I did that. Now the error coming out is as follows:-
TypeError: grid.mongo.GridStore is not a constructor
For this I am not getting any fixes on stack overflow or any other websites. Can someone please help

Cannot POST /images | MongoDB y Mongoose

I am developing a project with a friend in NodeJS and we are using express, Mongoose and when uploading images to the server it throws us this error: Cannot POST / images Here I leave the code in case someone can help me please:
const fs = ('fs-extra');
const path = ('path');
const md5 = ('md5');
const ctrl = {};
const Image = require('../models/image.js');
ctrl.create = (req, res) => {
const saveImage = async () => {
const imgUrl = randomNumber();
const images = await Image.find({ filename : imgUrl});
if(images.length > 0) {
saveImage()
} else {
const imageTempPath = req.file.path;
const ext = path.extname(req.file.originalname).toLowerCase();
const targetPath = path.resolve('/src/public/upload/${imgUrl}${ext}');
if(ext == '.png' || ext == '.jpg' || ext == '.gif' || ext == '.jpeg') {
await fs.rename(imageTempPath, targetPath);
const newImg = new Image({
filename: imgUrl + ext
});
const imageSaved = await newImg.save();
res.redirect('/images/' + imageSaved.uniqueId);
} else {
await fs.unlink(imageTempPath);
res.status(500).json({ error: 'Solo se permiten Imagenes'})
}
}
};
saveImage();
};
module.export = ctrl;
This is the controller that I have for uploading images and this is the model:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const path = require('path');
const ImageSchema = new Schema({
filename: { type: String }
});
ImageSchema.virtual('uniqueId')
.get(function () {
return this.filename.replace(path.extname(this.filename), '');
});
module.exports = mongoose.model('Image', ImageSchema);
And finally this is the route I use for uploading images (in addition to having some routes such as login and user registration):
const router = require('express').Router();
const passport = require('passport');
const multer = require('multer');
const path = require('path');
const fs = require('fs-extra');
const image = require('../controllers/image');
module.exports = app => {
router.post('/images', image.create);
}
router.get('/', (req, res, next) => {
res.render('index');
});
router.get('/signup', (req, res, next) => {
res.render('signup');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.get('/signin', (req, res, next) => {
res.render('signin');
});
router.post('/signin', passport.authenticate('local-signin', {
successRedirect: '/profile',
failureRedirect: '/signin',
failureFlash: true
}));
module.exports = router;
router.use((req, res, next) => {
isAuthenticated(req, res, next);
next();
});
router.get('/profile', (req, res, next) => {
res.render('profile');
});
router.get('/logout', (req, res, next) => {
req.logout();
res.redirect('/');
});
function isAuthenticated(req, res, next) {
if(req.isAuthenticated()) {
return next();
}
res.redirect('/')
}
I would appreciate it very much if you could help me
Thank you.
You need to use multer to save images in MongoDB according to THIS article.
The important takeaway here is that our data type is a Buffer, which allows us to store our image as data in the form of arrays.
const multer = require('multer');
mongoose.connect(‘url_here’);
const Item = new ItemSchema(
{ img:
{ data: Buffer, contentType: String }
}
);
const Item = mongoose.model('Clothes',ItemSchema);
app.use(multer({ dest: ‘./uploads/’,
rename: function (fieldname, filename) {
return filename;
},
}));
app.post(‘/api/photo’,function(req,res){
var newItem = new Item();
newItem.img.data = fs.readFileSync(req.files.userPhoto.path)
newItem.img.contentType = ‘image/png’;
newItem.save();
});
Or follow this post.
Store an image in MongoDB using Node.js/Express and Mongoose

Express.js why does placement of app.use() affect test results?

I am practicing my knowledge in Express.js .
I have one recipe router with the code below:
const express = require("express");
const router = express.Router();
const Recipe = require("../models/recipe.model");
const createRecipeItem = async recipeData => {
await Recipe.init();
const doc = Recipe(recipeData);
await doc.save();
};
router.post("/", async (req, res, next) => {
try {
await createRecipeItem(req.body);
} catch (err) {
next(err);
}
res.status(201).send(req.body);
});
module.exports = router;
I have another supply router, the code is below:
const express = require("express");
const router = express.Router();
const Supply = require("../models/supply.model");
const createSupplyItem = async supplyData => {
await Supply.init();
const doc = Supply(supplyData);
await doc.save();
};
const updateItem = async (name, itemData) => {
const result = await Supply.findOneAndUpdate({ name }, itemData, {
new: true
});
return result;
};
router.post("/", async (req, res, next) => {
try {
await createSupplyItem(req.body);
} catch (err) {
next(err);
}
const respObj = {};
respObj.name = req.body.name;
respObj.qty = req.body.qty;
res.status(201).send(respObj);
});
router.patch("/:name", async (req, res, next) => {
const updatedItem = await updateItem(req.params.name, req.body);
const response = {};
response.name = updatedItem.name;
response.qty = updatedItem.qty;
res.status(200).send(response);
});
module.exports = router;
I wrote tests for the two routers using supertest
Inside my app.js my code is written like this:
const supplyRouter = require("./routes/supply.route");
const recipeRouter = require("./routes/recipe.route");
app.use("/recipes", recipeRouter);
app.use("/supplies", supplyRouter);
when the code is written like this:
app.use("/recipes", recipeRouter);
app.use("/supplies", supplyRouter);
All my test passed. However, when I change the order of when I call app.use() the test would fail.
app.use("/supplies", supplyRouter);
app.use("/recipes", recipeRouter);
The test would fail with the error Cannot set headers after they are sent to the client for the POST /supplies method. I have no clear understanding why this happens. Appreciate any insight. Thank you!
I cannot pass my test correctly because I didn't have proper understanding of the flow of the code.
router.post("/", async (req, res, next) => {
try {
await createSupplyItem(req.body);
} catch (err) {
next(err);
}
const respObj = {};
respObj.name = req.body.name;
respObj.qty = req.body.qty;
res.status(201).send(respObj);
});
For the above code, when there is an error, express will run two paths of the code namely the path inside the catch block and the last line of the code
res.status(201).send(respObj);
Because it is trying to run two paths, I received the error Cannot set headers after they are sent to the client.
The correct code is written below.
router.post("/", async (req, res, next) => {
try {
await createSupplyItem(req.body);
const respObj = {};
respObj.name = req.body.name;
respObj.qty = req.body.qty;
res.status(201).send(respObj);
} catch (err) {
if (err.name === "ValidationError") {
err.statusCode = 400;
} else if (err.name === "MongoError") {
err.statusCode = 400;
}
next(err);
}
});

Creating folders by using object values

I am learning Nodejs, and I am trying to create folders for each new user.
The folder will be linked to the User name (when clicking on it will open folder/ftp)
I am using the Admin-bro interface.
Here is the User object.
const { model } = require("mongoose");
const User = model("User", {
name: String,
surname: String,
age: Number,
email: String,
description: String
});
module.exports = User;
User router:
const { Router } = require('express')
const paginate = require('../services/paginate.service')
const User = require('../models/user.model')
const dir = require('../routers/ftp')
const router = new Router()
const serializer = (user) => {
return user.toObject({ versionKey: false })
}
router.get('/', async (req, res) => {
const users = await paginate(User.find({}), req)
res.send(users.map(serializer))
})
router.post('/', async (req, res) => {
const user = await new User(req.body.user).save()
res.send(serializer(user))
})
module.exports = router
I have no idea how to create a folder for each new user I add, passing name_surname as the folder name.
I trying to create a router but failed.
This is what I tried:
"use strict";
module.exports = function(app) {
const fs = require("fs");
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
desctination: function(req, file, cb) {
const uploadDir = path.join(__dirname, "..", "..", `${Date.now()}`);
fs.mkdirSync(uploadDir);
cb(null, uploadDir);
},
filename: function(req, file, cb) {
cb(null, file.originalname);
}
});
const upload = multer({ storage });
const controller = require("../routers/createDir");
};
PS: there is no controller as I don't know what do to.
Please give me an advice or a link where I can learn how it's done. Thank you
User mkdrp node module package
var mkdirp = require('mkdirp');
mkdirp('/tmp/foo/bar/baz', function (err) {
if (err) console.error(err)
else console.log('pow!')
});
I am willing to pass the user name or id to the folder and create it dynamically, not manually. smth like this
const multer = require("multer");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const { userId } = req.body;
const dir = `../uploads/${userId}`;
fs.exists(dir, exist => {
if (!exist) {
return fs.mkdir(dir, error => cb(error, dir));
}
return cb(null, dir);
});
},
filename: (req, file, cb) => {
const { userId } = req.body;
cb(null, `UserId-${userId}-Image-${Date.now()}.png`);
}
});
const upload = multer({ storage });

Categories

Resources