My problem is I want to join this schema. Eg: In any e-commerce website there is a main image and after clicking that product we can see multiple image of that product. For uploading image I use multer package and in multer we cant upload single image and array of image in the same form so I create a new form that only takes an array of images. So I want to join that array of image data with my main form
This schema is to upload a single image:
const mongoose = require('mongoose');
const singleImageSchema = new mongoose.Schema({
file: {
type: mongoose.Schema.Types.ObjectId,
ref: 'File',
},
singleImage: {
type: String,
},
});
module.exports = new mongoose.model('File', singleImageSchema);
This schema is to upload multiple images:
const mongoose = require('mongoose');
const multipleImageSchema = new mongoose.Schema({
multipleImage: {
type: [String],
},
});
module.exports = new mongoose.model('Image', multipleImageSchema);
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require('ejs');
const mongoose = require('mongoose');
const multer = require('multer');
const path = require('path');
const helpers = require('./helpers');
const singleImage = require('./models/singleImage');
const multipleImage = require('./models/multipleImage');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads');
},
// By default, multer removes file extensions so let's add them back
filename: function (req, file, cb) {
cb(
null,
file.fieldname + '-' + Date.now() + path.extname(file.originalname),
);
},
});
const app = express();
app.set('view engine', 'ejs');
app.use(
bodyParser.urlencoded({
extended: true,
}),
);
app.use(express.static('public'));
//connect to database
mongoose.connect('mongodb://localhost:27017/ImageInDB', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log('Database is connected successfully on port 27017!!!');
});
app.get('/', (req, res) => {
res.render('file_upload');
});
app.post('/upload-profile-pic', (req, res) => {
let upload = multer({
storage: storage,
fileFilter: helpers.imageFilter,
}).single('profile_pic');
upload(req, res, function (err) {
if (req.fileValidationError) {
return res.send(req.fileValidationError);
} else if (!req.file) {
return res.send('Please select an image to upload');
} else if (err instanceof multer.MulterError) {
return res.send(err);
} else if (err) {
return res.send(err);
}
const oneImage = new singleImage({
singleImage: req.file.filename,
});
oneImage.save(err => console.log(err));
// Display uploaded image for user validation
singleImage.find({}, (err, product) => {
res.render('preview', {
product: product,
});
});
});
});
app.post('/upload-multiple-images', (req, res) => {
let upload = multer({
storage: storage,
fileFilter: helpers.imageFilter,
}).array('multiple_images', 10);
upload(req, res, function (err) {
if (req.fileValidationError) {
return res.send(req.fileValidationError);
} else if (!req.files) {
return res.send('Please select an image to upload');
} else if (err instanceof multer.MulterError) {
return res.send(err);
} else if (err) {
return res.send(err);
} // The same as when uploading single images
const files = req.files;
const moreImage = new multipleImage({
multipleImage: files.map(file => file.filename),
});
moreImage.save(err => console.log(err));
// Loop through all the uploaded images and display them on frontend
multipleImage.find({}, (err, products) => {
res.render('multiPreview', {
products: products,
});
});
});
});
app.listen(3000, function () {
console.log('Server started on port 3000');
});
You need to add reference schema to singleImageSchema and then use populate() method like this:
const singleImageSchema = new mongoose.Schema({
file: {
type: mongoose.Schema.Types.ObjectId,
ref: 'File',
},
singleImage: {
type: String,
},
multipleImage: [{ type: Schema.Types.ObjectId, ref: 'Image' }]
});
then your query will become
singleImage
.find()
.populate('multipleImage')
.exec(function(err, result) {
});
Documentation for populate() method: https://mongoosejs.com/docs/populate.html
Instead why you are not adding in single table?
Related
Adding collections manually is easy but adding it dynamically giving me unexpected answer.
I am getting a collection name from frontend to backend using promt and axios but when I am doing
const variable_from_frontEnd = mongoose.model(variable_from_frontEnd, Schema);
it is not adding any collections.
import express from "express";
import mongoose from "mongoose";
import Messages from "./messages.js";
import cors from "cors";
// app configuration
const app = express();
const port = process.env.PORT || 9000;
const pusher = new Pusher({
appId: "1183689",
key: "c9fa659fc6b359a23989",
secret: "9da56a5db535e10c7d95",
cluster: "eu",
useTLS: true
});
//middleware
app.use(express.json());
app.use(cors());
// DB Configuration
const url = "mongodb+srv://suraj_bisht_99:zoe6B82AZjaLXgw7#cluster0.zp9dc.mongodb.net/Whatsapp_MERN?retryWrites=true&w=majority";
mongoose.connect(url, {useCreateIndex: true, useNewUrlParser: true, useUnifiedTopology: true})
.then(()=> console.log('mongoDB is connected'))
.then(err => console.log(err));
const groupSchema = mongoose.Schema( {
message: String,
name: String,
timestamp: String,
received: Boolean,
});
// API routes
app.get("/", (req, res) => {
res.status(200).send("Hello World");
})
app.get("/messages/sync", async (req, res) => {
await Messages.find( (err, data) => {
if(err){
console.log(err);
res.status(500).send(err);
}else{
res.status(200).send(data);
}
})
})
app.post("/messages/new", async (req, res) => {
try{
const newMessage = new personalGroup(req.body);
const newMessageCreated = await newMessage.save();
res.status(201).send(newMessageCreated);
}
catch(err){
res.status(400).send(err);
}
});
// route for creating new collection in mongoDB
app.post("/room/new", async (req, res) => {
try{
let groupName = req.body.room;
groupName = mongoose.model(groupName, groupSchema);
if(!groupName){
console.log("error is occured");
}else{
console.log(groupName);
}
}
catch(err){
res.status(400).send(err);
}
})
// listening part
app.listen(port, () => console.log(`listening on port number ${port}`));
Let's say I have type a collection name "studyGroup" from frontend then
console is giving me
Model { studyGroup }
Can someone help me why it is happening and how can I add collections manually.
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
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 });
So I am making this website where you can see different recipes for food. When browsing for recipes, I want the user to be able to select a category and browse all the dishes that fall under it (i.e dessert, dinner, vegan etc).
I have this function I created in my router file that returns all the dishes that fall under the specified category:
router.get('/showrecipes/:categoryname', (req, res, next) => {
let nameQuery = {category: req.params.categoryname};
Recipe.find(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
However, when I try to test it out in Postman, I keep getting Null instead of all the dishes that fall under the category.
All my other functions are correctly working, but this one seems to have issues.
For reference, here is the rest of the recipeRouter file:
const express = require('express');
const passport = require('passport');
const Recipe = require('../models/recipe');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
router = express.Router();
router.get('/', (req, res, next) => {
res.json('Here are the recipes!')
});
// Is working
router.get('/showrecipes', (req, res, next) => {
Recipe.find({}, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
// Is working.
router.get("/showrecipes/:recipename", (req, res, next) => {
let nameQuery = {name: req.params.recipename};
Recipe.findOne(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
})
});
// Is not crashing, but is returning Null which isn't how it's supposed to work.
router.get('/showrecipes/:categoryname', (req, res, next) => {
let nameQuery = {category: req.params.categoryname};
Recipe.find(nameQuery, (err, recipes) => {
if (err) throw err;
res.json(recipes);
});
});
// Now it's working, good stuff.
router.post('/addrecipe', (req, res, next) => {
Recipe.create({
name: req.body.name,
description: req.body.description,
steps: req.body.steps,
ingredients: req.body.ingredients,
category: req.body.category,
}, (err, recipe) => {
if (err) throw err;
// Recipe.save();
res.json(recipe);
});
});
// See if this works
router.put('editrecipe/:recipename/:editedField', (req, res, next) => {
Recipe.findOneAndUpdate({name: req.params.recipename}, {$set: req.body}, {new: true}, (err, recipe) => {
if (err) throw err;
res.json(recipe)
});
});
// It's working, thank god
router.delete('/deleterecipe/:recipename', (req, res, next) => {
let nameQuery = {name: req.params.recipename};
Recipe.findOneAndRemove(nameQuery, (err, recipe) => {
if (err) throw err;
res.send('Dish was succesfully deleted!')
});
});
module.exports = router;
And here is my app.js file
let express = require('express');
let mongoose = require('mongoose');
let path = require('path');
let bodyParser = require('body-parser');
let recipeRouter = require('./routes/recipeRouter');
let userRouter = require('./routes/userRouter');
let bcrypt = require('bcrypt');
let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
let config = require('./config');
mongoose.connect(config.mongoUrl);
let db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
// we're connected!
console.log("Connected correctly to server");
});
const app = express();
const port = 3000;
app.listen(port);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.set('views', path.join(__dirname, 'views'));
app.use('/users', userRouter);
app.use('/recipes',recipeRouter);
app.get('/', function(req, res){
res.send('Hey, this is your database!')
});
module.exports = app;
And here is my Recipe file
const express = require('express');
const mongoose = require('mongoose');
const User = require('../models/user');
let Schema = mongoose.Schema;
let commentSchema = Schema({
rating: {
type: Number,
required: true,
min: 1,
max: 5,
},
comment: {
type: String,
required: true
},
postedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
let Comment = mongoose.model('Comment', commentSchema);
let recipeSchema = Schema({
name: {
type: String,
required: true
},
description: {
type: String,
},
steps: {
type: String,
required: true,
},
ingredients: {
type: Array,
required: true
},
comments: [commentSchema],
category: {
type: String,
required: true,
},
postedBy: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
/// So I learnt that by defining the string as "Recipe" in the model function, I will have to lower case it
/// and pluralize it when I use it with res.json and other such things (i.e. "Recipe" => recipes).
let Recipe = mongoose.model('Recipe', recipeSchema);
module.exports = Recipe;
/// refactor this so that these are in the router, not in the models file
/*
module.exports.getRecipeByName = (name, callback) => {
let nameQuery = {name: name};
Recipe.findOne(nameQuery, callback);
};
module.exports.getRecipesByCategory = (category, callback) => {
Recipe.find({'category': category});
};
*/
var express = require("express");
var app = express();
var mongoose = require("mongoose"),
bodyParser = require("body-parser"),
methodOverride = require("method-override"),
Book = require("./models/book"),
multer = require('multer');
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'uploads/');
},
filename: function (request, file, callback) {
console.log(file);
callback(null, file.originalname)
}
});
var upload = multer({ storage: storage });
mongoose.Promise = global.Promise;
mongoose.connect("mongodb://localhost/books")
app.set("view engine", "ejs")
app.use(express.static(__dirname + "/public"))
app.use(methodOverride("_method"));
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", function (req, res) {
res.redirect("/books")
})
//Add new book
app.get("/books/new", function (req, res) {
res.render("books/new.ejs")
})
//CREATE BOOK logic
app.post("/books", upload.single('photo'), function (req, res, next) {
var name = req.body.name;
var price = req.body.price;
var desc = req.body.desc;
var newBook = { name: name, price: price, desc: desc }
// I want to change the name of image same as the id of this database data
Book.create(newBook, function (err, newlyCreated) {
if (err) {
console.log(err)
} else {
res.redirect("/books")
}
})
})
//SHOW page
app.get("/books/:id", function (req, res) {
Book.findById(req.params.id).exec(function (err, foundBook) {
if (err) {
console.log(err)
} else {
res.render("books/show.ejs", { books: foundBook });
}
})
})
app.get("*", function (req, res) {
res.send("Error 404");
});
app.listen(3000, function () {
console.log("server started");
});
Here is my app.js file. Now I want to save the image name same as the object id of that specific book data which is generated in database(mongoDB). How can I change the name of file(which is inside storage, filename) in app.post function.
The second argument to your callback in the filename function is whatever string you want to set it to, so just set it to the UUID you get from the id mongoose creates for you.
Example added based on comments.
var storage = multer.diskStorage({
destination: function (request, file, callback) {
callback(null, 'uploads/');
},
filename: function (request, file, callback) {
if (request.book) {
// TODO: consider adding file type extension
return callback(null, request.book.id.toString());
}
// fallback to the original name if you don't have a book attached to the request yet.
return callback(null, file.originalname)
}
});
I often solve multistep handlers (e.g. creating a book, uploading a book, responding to the client) by breaking the steps down into individual middleware. For example:
var upload = multer({ storage: storage });
function createBook(req, res, next) {
var name = req.body.name;
var price = req.body.price;
var desc = req.body.desc;
var newBook = { name: name, price: price, desc: desc }
// I want to change the name of image same as the id of this database data
Book.create(newBook, function (err, newlyCreated) {
if (err) {
next(err)
} else {
req.book = newlyCreated;
next();
}
})
}
app.post('/books', createBook, upload.single('photo'), function(req, res) {
// TODO: possibly return some code if there's no book, or redirect to the individual book page
res.redirect('/books');
});
// add error handler for one-stop logging of errors
app.use(function(err, req, res, next) {
console.log(err);
next(err); // or you can redirect to an error page here or something else
});
Here is an example
var data = { title: "new title" };
var options = { new: true };
MyModel.create (query, data, options,
function(err, doc) {
//here you got id
console. log(doc._id)
// save your file here
});