How to add user profile picture in schema - node.js

I have to develop an application in which the user has a profile picture in his schema. I am using gridfs (MongoDB). how can I access the specific picture of a user? if I upload a picture it will show on every user profile how can I make it unique?
// This is my user schema I want to add a profile picture here but I don't know how to do it?
const Joi = require('joi');
const mongoose = require('mongoose');
const config = require('config');
const User = mongoose.model('User', new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 5,
maxlength: 50
},
email: {
type: String,
required: true,
minlength: 5,
maxlength: 255,
unique: true
},
password: {
type: String,
// required: true,
minlength: 5,
maxlength: 1024
},
isVerified: {
type: Boolean,
default: false
}
}));
//This is my post image API I am using gridfs as a middle ware in it
const uploadFiles = async (req, res) => {
try {
await upload(req, res);
console.log(req.file);
if (req.file == undefined) {
return res.send({
message: "You must select a file.",
});
}
return res.send({
message: "File has been uploaded.",
});
} catch (error) {
console.log(error);
return res.send({
message: "Error when trying upload image: ${error}",
});
}
};
//Gridfs middleware code
const util = require("util");
const multer = require("multer");
const { GridFsStorage } = require("multer-gridfs-storage");
const dbConfig = require('../config/db')
var storage = new GridFsStorage({
url: dbConfig.url + dbConfig.database,
options: { useNewUrlParser: true, useUnifiedTopology: true },
file: (req, file) => {
const match = ["image/png", "image/jpeg"];
if (match.indexOf(file.mimetype) === -1) {
const filename = `${Date.now()}-image-${file.originalname}`;
return filename;
}
return {
bucketName: dbConfig.imgBucket,
filename: `${Date.now()}-image-${file.originalname}`
};
}
});
var uploadFiles = multer({ storage: storage }).single("file");
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;
//Image get API request
const getListFiles = async (req, res) => {
try {
await mongoClient.connect();
const database = mongoClient.db(dbConfig.database);
const images = database.collection(`${dbConfig.imgBucket}.files`);
const cursor = images.find({});
if ((await cursor.count()) === 0) {
return res.status(404).send({
message: "No files found!",
});
}
let fileInfos = [];
await cursor.forEach((doc) => {
fileInfos.push({
name: doc.filename,
url: baseUrl + doc.filename,
});
});
return res.status(200).send(fileInfos);
} catch (error) {
return res.status(500).send({
message: error.message,
});
}
};
//Routes
router.post('/upload', uploadFiles);
router.get('/files', getListFiles)
Images are stored in the image bucket and also I can get them too but I do not know how to get them as a user-specified image.

Add profilePictureURL as a string type in schema.
profilePictureURL: { type: String }
Save Profile Picture to User's Profile picture or any folder with
current date or user's _id or any unique Value to make it unique.
For Ex. if you save your image into public/user/profile_picture
profilePictureURL = 'public/user/profile_picture/'+user._id
Retrieve that profilePictureURL and access them using
baseURL + profilePictureURL

Mongo DB generates _id to each and every obj. You can store your image URL on the User scheme and while fetching the user you can get a specific image based on the User.
You can also use Populate fields(Like Joins) on User schema where you can store image id on user and while fetching you can populate entire image object with User itself.
You need to update your schema with the references.
const UserSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
stories: [{ type: YourIdType(Eg. Schema.Types.ObjectId), ref: 'YourImageCollectionName' }]
});

Related

how to upload image files to server and MongoDB

React.js Node.js Express.js Axios Multer MongoDB Mongoose
Wrote this form to register users, the user enters name, email, password, and a file for later use as profile pic/Avatar.
When i tested the form on Postman the opposite has happened, the file was uploaded to the public/uploads/images folder but it didnt post to the user with the rest of the registration data i entered.
But when i tested the form on localhost domain the image filename was saved on the user's Avatar value MongoDB nut was'nt uploaded to the servers folder i chose to upload my uploaded files.
wanted end result:
to register user to websites database with all parameters, uploading the image to the server and image filename to users avatar data
Register Route
router.post("/register", upload.single("avatar"), async (req, res) => {
try {
const validatedValue = await validateRegisterSchema(req.body);
const user = await findUserByEmail(validatedValue.email);
if (user) throw "try different email";
const hashedPassword = await createHash(validatedValue.password);
validatedValue.password = hashedPassword;
await createNewUser(validatedValue);
res.status(201).json({ msg: "user created"});
} catch (error) {
res.status(400).json({ error });
}
});
Multer
destination: (req, file, cb) => {
cb(null, "./public/uploads/images/");
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
if (err) return cb(err);
cb(null, file.originalname);
});
},
});
const fileFilter = (req, file, cb) => {
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage,
limit: {
fileSize: 1024 * 1024 * 10,
},
fileFilter,
});
User Model
const Schema = mongoose.Schema;
const usersSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
wishList: { type: Array },
isAdmin: { type: Boolean, default: false },
avatar: { type: String },
});
const Users = mongoose.model("users", usersSchema);
const createNewUser = (userData) => {
const newUser = new Users(userData);
return newUser.save();
Solved
prior code:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0].name;
setUserInput(newUserInput);
};
sulution:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0]; // removed ".name" left it as file object
setUserInput(newUserInput);
};

Image url in mongodb by using multer and local storage of machine

I want to store the image URL in my MongoDB collection using multer and machine storage. I tried to follow one tutorial but it is not generating the correct URL I am posting my code here too. Can someone please guide me? I am very new to storing data in the database.
This is my model file:
const mongoose = require(‘mongoose’);
const User = mongoose.model(‘User’, new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
image: {
type: String
}
}));
exports.User = User;
This is my multer middleware:
const store = multer.diskStorage({
destination: function (req, file, cb) {
fs.mkdir(path, { recursive: true}, function (err) {
if (err) return cb(err);
cb(null, “uploads/photos”);
});
},
filename: function (req, file, cb) {
const name = file.originalname.toLowerCase().split(’ ‘).join(’_’);
cb(null, name + ‘-’ + Date.now());
}
});
const upload = multer({ storage: store }).single(‘image’);
This is my post router:
function CreateUser(req, res) {
const url = req.protocol + ‘://’ + req.get(“host”);
let user = new User(
{
name: req.body.name,
email: req.body.email,
image: url + ‘/images/’ + req.file.filename
}
);
user.save()
.then(data => {
res.send(data);
}).catch(err => {
res.status(500).send({
success: false,
message: err.message || “Some error occurred while creating the user.”
});
});
};
router.post(’/create’, [upload], CreateUser);
And in last I use the path npm module to join it in my server.js file so that I can get it to frontend also.
app.use("/images", express.static(path.join("uploads/photos")));
When I run in postman it is generating this URL:
http://localhost:5000/images/picture.png-1655124752174
And I can't access this URL, Can anyone please help me with this code I am stuck here?
I followed this tutorial to make this:
https://www.javatpoint.com/working-with-file-url-in-mean-stack

insert an array of object ids mongoose nodejs

I want to be able to post several Object id's into the array,, I have two models control and subcontrol is referenced in the control model as an array. The idea is a control number might have sub control number under it
My post method:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControls = []
for(const subControl of req.body.subControls){
const tableSubControl ={
subControlNo: subControl.subControlNo
};
const newSubControls = new SubControl(tableSubControl);
const subControlDoc = await newSubControls.save();
const control = new Control({...req.body, subControl: subControlDoc._id});
const savedControl = await control.save();
subControls.push(newSubControls)
}
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
Control Schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [
{
type: Mongoose.Schema.Types.ObjectId,
ref: 'SubControl'
}
],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
My subControl schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Postman:
{
"mainControl": "1-1",
"subControls":
[
{
"subControlNo": "1-2-1"
},
{
"subControlNo": "1-2-2"
}
],
"controlDescription": "controldescription"
}
I'm not getting any clear error,, any idea what I need to do?
Well I am guessing when you create new Control object from req.body then don't set subControl:subcontrol._id there. Instead a object subcontrol should be assigned to Control object.
const subControlDoc = await newSubControls.save();
const control = new Control({...req.body});
control.subcontrol = subControlDoc
const subControlDoc = await newSubControls.save();
const savedControl = await control.save();
subControls.push(newSubControls)
We can manage this using Population :
Consider the following changes in the code, I have tried adding comments too.
router.post(
"/add",
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
//first create a single control document
const control = new Control({
mainControl: req.body.mainControl,
controlDescription: req.body.controlDescription,
});
//nitpick: the for loop below can be made async.
for (const subControl of req.body.subControls) {
const tableSubControl = {
subControlNo: subControl.subControlNo,
};
const newSubControls = new SubControl(tableSubControl);
const subControlDoc = await newSubControls.save();
//save the looped subControl document
control.subControls.push(subControlDoc);
//push the association to the control document.
}
//save the control document, moved outside the loop
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl,
});
} catch (error) {
return res.status(400).json({
error,
// error: 'Your request could not be processed. Please try again.'
});
}
}
);

i am trying to add multiple users on a atlas mongoDB

I have created a rest api and I am trying to add multiple users to atlas mongodb I use this schema
const mongoose = require('mongoose');
const { v1: uuidv1 } = require('uuid');
const crypto = require('crypto')
const userSchema = new mongoose.Schema({
// _id: mongoose.Types.ObjectId,
name: {
type: String,
// trim: true,
unique: true,
required: true,
index: true
},
email: {
type: String,
// trim: true,
required: true,
unique: true,
},
hashed_password: {
type: String,
trim: true,
required: true
},
salt: String,
created: {
type: Date,
default: Date.now
},
updated: Date,
})
// VIRTUAL FIELD
userSchema.virtual('password')
.set(function(password){
//create temporary variable called _password
this._password = password
//generate a timestamp
this.salt = uuidv1();
//encryptPassword
this.hashed_password = this.encryptPassword(password)
})
.get(function(){
return this._password
})
///methods
userSchema.methods = {
authenticate: function(plainText){
return this.encryptPassword(plainText) === this.hashed_password
},
encryptPassword : function(password){
if(!password) return "";
try{
return crypto.createHmac('sha256', this.salt)
.update(password)
.digest('hex');
} catch(err){
return ""
}
}
}
module.exports = mongoose.model('User', userSchema);
I use this function to sign up :
exports.signup = async (req, res) => {
const userExists = await User.findOne({email : req.body.email})
if(userExists) return res.status(403).json({
error: "EMAIL is TAKEN"
})
const user = await new User(req.body)
await user.save()
.then(result => {res.json({result: result})})
.catch(err => res.json({err : err}))
}
I validate :
exports.userSignupValidator = (req, res, next) => {
//name is not null and its between 4 and 10 characters
req.check('name', 'name is required').notEmpty();
//email is not null, valid and NORMALIZED -> we will use method chaining
req.check('email', 'please enter valid email')
.matches(/.+\#.+\..+/)
.withMessage('email must contain #')
.isLength({
min: 4,
max: 2000
})
//check for password
req.check('password', 'Password is required').notEmpty();
req.check('password').isLength({
min: 6,
}).withMessage('password must be minimum 6 char long').matches(/\d/).withMessage('must contain a number')
//check for errors
const error = req.validationErrors()
////////if error apears show the first one as they appear
if(error){
const firstError = error.map((error) => error.msg)[0]
return res.status(400).json({error: firstError})
}
////proceed to next middleware
next()
}
and I use the route :
const express = require('express'); //bring in express
const postController = require('../controlers/postControler') //brings everything that is exported from the postControler FILE and becomes a OBJECT
const router = express.Router();
const validator = require('../validator');
const signup = require('../controlers/authControler');
const userById = require('../controlers/userControler');
router.get('/', postController.getPosts)
router.post('/post', signup.requireSignIn, validator.createPostValidator, postController.createPost)
router.get('/test' , postController.test)
router.post('/signup', validator.userSignupValidator, signup.signup)
router.post('/signin', signup.signin)
router.get('/signout', signup.signout)
router.get('/lahoha', userById.getUsers)
////find the user by id with params
////any routes containing :userId our app will first execute userById()
router.param('userId', userById.userById);
///////////////////////////////////////////////
module.exports = router
the problem is when I try to create a second user with postman with :
{
"name": "petru",
"email": "petru#gmail.com",
"password": "notazece10"
}
I get the error :
{
"err": {
"driver": true,
"name": "MongoError",
"index": 0,
"code": 11000,
"keyPattern": {
"username": 1
},
"keyValue": {
"username": null
}
}
}
Please help !!!!! this error is driving me crazy, I don't know what I'm doing wrong
after running thru my code multiple times line by line i found out the code is fine , the problem was in my atlas mongodb database.
So i am new to nodejs and mongo , and i try to learn , when i created my first mongodb database in atlas i did not pay attention to naming my database so it had the default name of .
I went back to atlas mongodb and i made a new database ( cluster) , named it TEST , copied the link, went into my dotenv file paste the link to my MONGO_URI restarted the server and then all code worked fine now i can add as many users as i want.
I hope other newcomers to mongodb and nodejs learn from my mistake and if someone ever repeats my STUPID mistake i hope they find this and fix it.

I want to upload images to my database using mongoose-gridfs. but i'm having trouble with that

I want to upload images using mongoose-gridfs. And I am having the following Problem (The one I show below in the photo). It is with the use of mongoose-gridfs and I would like if someone has worked with this library and in the way that I structure it below, it will help me to solve my situation or update me if there is a newer way to do it following this same structure. Thanks in advance.
This image show the error when i try to execute my code
Here my model Attachment
'use strict'
const mongoose = require('mongoose');
const gridfs = require('mongoose-gridfs')({ // TypeError: require(...) is not a function
collection: 'attachments',
model: 'Attachment'
});
const AttachmentSchema = gridfs.schema;
module.export = mongoose.model('Attachment', AttachmentSchema);
Here my model User where I pass Attachment as ref to the photo atributte
'use strict'
require('mongoose-type-email');
const bcrypt = require('bcrypt-nodejs');
const crypto = require('crypto');
const uniqueValidator = require('mongoose-unique-validator');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
first_name: {type: String, required: true},
email: {type: mongoose.SchemaTypes.Email, required: true, unique: true},
password: {type: String, required: true},
active: {type: Boolean, default: false},
created: {type: Date, default: Date.now()},
photo: {type: Schema.ObjectId, ref: "Attachment"},
valid_token: {type: String},
});
Now my fileService.js service that I use to upload the images.
'use strict'
const Attachment = require('../models/Attachment');
const im = require('imagemagick');
const fs = require('fs');
const events = require('events');
const gridfs = require('mongoose-gridfs')({ //TypeError: require(...) is not a function
collection: 'attachments',
model: 'Attachment'
});
exports.uploadFile = function (file, cb) {
const eventEmitter = new events.EventEmitter();
const lista = Object.values(file);
const properties = Object.getOwnPropertyNames(file);
const result = [];
const listLength = lista.length;
eventEmitter.once('err', err => {
cb(err);
});
eventEmitter.once('upload', lista => {
cb(null, lista);
});
eventEmitter.on('uploadFinish', (obj, property) => {
obj.contentType.startsWith("image") ? result.push({
type: 'img',
'property': property,
'value': obj
}) : result.push({type: 'video', 'property': property, 'value': obj})
if (listLength == result.length)
eventEmitter.emit("upload", result);
});
lista.length != 0 ? fileWrite(lista, properties, eventEmitter) : eventEmitter.emit("upload");
};
function fileWrite(lista, properties, eventEmitter) {
const files = Array();
const Attachment = gridfs.model;
lista.forEach((element, index) => {
Attachment.write({
filename: element.name,
contentType: element.type
},
fs.createReadStream(element.path),
(err, createdFile) => {
err ? eventEmitter.emit('err', err) : eventEmitter.emit('uploadFinish', createdFile,
properties[index]);
});
});
}
Here is my userService.js where I call the uploadFile function of the fileService.js service
'use strict'
const User = require('../models/User');
const fileService = require('../services/fileService');
exports.save = function (file, data, res) {
fileService.uploadFile(file, (err, files) => {
if (!err) {
if (files) {
files.forEach((e) => {
if (e.property == "photo") {
data.photo = e.value;
}
});
}
data['created'] = new Date();
const user = new User(data);
user.save((err, user) => {
if (!err) {
user.update(data, (error) => {
if (!error) {
res.json({success: true, message: "Inserted user", data: user})
} else {
res.send({
success: false,
message: 'User cant be updated'
});
}
});
} else
res.status(500).send({success: false, message: 'Error trying to save the user'});
});
} else {
res.status(500).send({success: false, message: 'Error trying to upload files'});
}
});
};
mongoose-gridfs specifies a different way of using it here:
const { createModel } = require('mongoose-gridfs');
etc.
See here for your specific error.

Resources