i have two collection in my db "users" and "forms"
each user has a table of forms
i used populate method to do this and it works
this is the model of user:
const Schema = mongoose.Schema
const UserSchema = new Schema({
firstName: {
type: 'string',
required: ' Firstname is Required'
},
lastName: {
type: 'string',
required: ' lastName is Required'
},
email: {
type: 'string',
required: ' email is Required'
},
phone: {
type: 'string',
},
entrprise: {
type: 'string'
},
password: {
type: 'string',
required: ' password is Required'
},
forms: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Form"
}
]
})
const User = mongoose.model('User', UserSchema)
module.exports = User
this the model of form
const Schema = mongoose.Schema
const FormSchema = new Schema({
logo: {
type: String,
},
compagnyName: {
type: String,
},
title: {
type: String,
},
description: {
type: String,
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
cardQuestion: [
{
questionTitle: String,
questionType: String,
questionCourte: String,
questionLongue: String,
choixMultiple: String,
caseaCocher: String,
telechargerFichier: String,
date: Date,
heure: String,
delete: false,
obligatoire: false,
}
]
})
const Form = mongoose.model('Form', FormSchema)
module.exports = Form
and this is how i use populate method
const getUser = async (req, res) => {
try {
const { userId } = req.params;
if (!userId) return res.status(400).json({ message: "ERROR ID!" });
const result = await User
.findById(userId).populate('forms')
.exec()
return res.status(200).json({ message: "Success", result });
} catch (err) {
res.status(500).json({ message: "INTERNAL ERROR SERVER!" });
console.log(err.message);
}
};
i added a user with forms using postman with the post method
when i try to add a form with react
const response = await axios.post(`${API_URL}/form/:userId`,
{
...form,
userId: localStorage.getItem('userId')
},
{
headers: {
authorization: localStorage.getItem('userId')
}
}
i get the form with the user id like this:
{
"_id": "6022916bf1d1060f84bc17d0",
"compagnyName": "axa",
"description": "recruitement",
"userId": "60214c5ec0491fcb2d8c29e8",
"__v": 0,
"cardQuestion": []
},
i find the new form in the forms collection but when i get the user ,the forms field doesn't update (still empty if i don't add the table of forms manually)
"result": {
"forms": [],
"_id": "60214c5ec0491fcb2d8c29e8",
"firstName": "moon",
"lastName": "lea",
"email": "moon15#gmail.com",
"password": "$2b$10$bnH0cEBQKktgaKHfBac3L.xUUNEYt9HaqKdLKxLOERrHPG4MVPPFS",
"phone": "087654266377",
"__v": 0
}
}
this is how i add a user
const register = async (req, res) => {
try {
const { firstName, lastName, email, phone, password, forms } = req.body
if (!firstName || !lastName || !email || !phone || !password)
return res.status(400).json({ message: 'ERROR!' })
//CHECKING EXISTING USER
const found = await User.findOne({ email })
console.log(found)
if (found) return res.status(400).json({ message: 'Email already exist' })
console.log(found)
//HASHING THE PASSWORD
const hashPassword = await bcrypt.hash(password, saltRounds)
console.log(hashPassword)
//CREATING THE NEW USER
const newUser = new User()
newUser.firstName = firstName
newUser.lastName = lastName
newUser.email = email
newUser.password = hashPassword
if (phone) newUser.phone = phone
if (forms) newUser.forms = forms
console.log('i')
//SAVING THE NEW USER
const result = await newUser.save()
console.log(result)
if (!result) return res.status(400).json({ message: 'failed to create user' })
can someone help?
maybe you have to change .populate('forms') in getUser to .populate('form')
i think it save it in singular shape
Related
My question is easy enough. i just cant come up with the logic myself. I created an api for a social media website using MERN stack. I added a 'get timeline' route that returns all the posts of the people that the current user has friended in addition to the own user's posts. Whenever a user adds a friend, the id of that friend is stored in an array in the mongoDB model. How do i filter the data coming back from the post model to only return the posts of the friend IDs inside the friends array in addition to the posts of the current user also.
The User model:
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: [true, 'please provide your first name'],
maxlength: 50,
minlength: 2
},
lastName: {
type: String,
required: [true, 'please provide your last name'],
maxlength: 50,
minlength: 2
},
email: {
type: String,
required: [true, 'please provide an email'],
match: [
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
'Please provide a valid email',
],
unique: true,
},
password: {
type: String,
required: [true, 'please provide a password'],
minlength: 8
},
image: {
type: String,
},
friends: {
type: Array,
default: [],
},
location: String,
occupation: String,
},
{ timestamps: true }
)
The timeline route:
router.get("/:id/timeline", getTimelinePosts)
The add or remove friend controller:
const addRemoveFriend = async (req, res) => {
const {id: userId, friendId} = req.params
const user = await User.findOne({_id: userId})
const friend = await User.findOne ({_id: friendId})
if(user.friends.includes(friendId)){
user.friends = user.friends.filter((_id) => _id !== friendId)
friend.friends = friend.friends.filter((_id) => _id !== userId);
}else{
user.friends.push(friendId);
friend.friends.push(userId);
}
await user.save();
await friend.save();
const friends = await Promise.all(
user.friends.map((_id) => User.findById(_id))
);
const formattedFriends = friends.map(
({ _id, firstName, lastName, location, image}) => {
return { _id, firstName, lastName, location, image};
}
);
res.status(200).json({formattedFriends});
}
You can use $in Operator to iterate over all the friends Ids and get the related post.
router.get("/get-timeline", async (req, res) => {
try {
const Posts = await mongoose.connection.db.collection('post')
const { id: userId } = req.params
//get the user record
const user = await User.findOne({ _id: userId })
//List of friends Id
const friendsList = user.friends
// I'm assuming in Post collection you have the field createdBy(assuming) to refer which user has created the post.
let postData = await Posts.find({ createdBy: { $in: friendsList } })
if (postData) {
return res.status(200).json({ success: true, data: postData })
} else {
console.log("Error while getting post data", err)
return res.status(500).json({ success: false, message: err })
}
} catch (err) {
console.log("Error while getting post data", err)
return res.status(500).json({ success: false, message: err })
}
})
I try to make one method for signup to two types of user ' buyer and seller ' .
When I save seller , I should get all information about their ' storeinfo ' , see my updated code below .
I used populate() but I get an empty array .
Is my idea wrong ?
code for signup
exports.signupUser = async (req, res, next) => {
role = req.body.role
const user = new User(req.body)
const seller = new Seller(req.body)
try{
if(role=='seller'){
await seller.save()
await user.save()
const token = await user.generateToken()
res.status(200).send({
error: null,
apiStatus:true,
data: {user,seller ,token}
})
}
await user.save()
const token = await user.generateToken()
res.status(200).send({
error: null,
apiStatus:true,
data: {user, token}
})
}
catch(error){
res.status(400).send({
error: error.message,
apiStatus:false,
data: 'unauthorized user'
})
}
}
code for login
exports.login = async (req, res) => {
try{
const user = await User.findUserByCredentials(req.body.email, req.body.password)
const token = await user.generateToken()
console.log(user.role)
if(user.role=='seller'){
console.log(user._id)
await User.findOne({_id: user._id}).populate('storeinfo').exec(function(err, user) {
if (err) {console.log(err)}
res.status(200).send({
error: null,
apiStatus:true,
user,token
})})
}
res.status(200).send({
error: null,
apiStatus:true,
data: {user, token}
})
}
catch(error){
res.status(400).send({
error: error.message,
apiStatus:false,
data: 'Something went wrong'
})
}
}
schema user
const userSchema = new Schema({
first_name: { type: String,required:true},
last_name: { type: String,required:true},
email: { type: String, unique: true, required: true, trim: true,lowercase: true ,validate(value) {
if (!validator.isEmail(value)) throw new Error("Invalid Email"); },
},
password: { type: String,minlength: 6,required: true, trim: true, match: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/},
role: { type: String, enum: ['admin','seller', 'user'], default: 'user' ,required: true},
mobileNumber: { type: String,default:'',trim: true,
validate(value) {
if (!validator.isMobilePhone(value, ["ar-EG"]))
throw new Error("invalid phone number");
},
},
address: {
type: String,
required: true,
trim: true
},
storeinfo:{
type: mongoose.Schema.Types.ObjectId,
ref:'Seller',
},
tokens: [{
token: {
type: String,
required: true
}
}]
}, {
timestamps: true
})
userSchema.methods.generateToken = async function(){
const user = this
const token = jwt.sign({_id: user._id.toString() , role:user.role}, process.env.JWTKEY)
user.tokens = user.tokens.concat({token})
await user.save()
return token
}
// login
userSchema.statics.findUserByCredentials = async(email, password)=>{
const user = await User.findOne({email})
if(!user) throw new Error('invalid email')
const matched = await bcrypt.compare(password, user.password)
if(!matched) throw new Error('invalid password')
return user
}
const User = mongoose.model('User', userSchema)
module.exports = User
seller schema
const SellerSchema = new Schema(
{
storeName: {
required: true,
type: String,
},
category: {
type: String,
required: true
},
image: {
type: String,
// required: true,
},
addresses:[
{
street: String,
locality: String,
aptName: String,
lat: Number,
lng: Number,
}
],
numberOfBranches: Number,
_userId:{ type: Schema.Types.ObjectId, ref: 'User'},
items: [{ type: Schema.Types.ObjectId, ref: "Item" }]
},
{ timestamps: true }
);
const Seller = mongoose.model('Seller', SellerSchema)
module.exports = Seller
I'm creating a web application that has chats, and users can join the chat. Once the user joins the chat, I want to add the user's ID as well as their name to the users field in the Chat schema. So far, I'm able to add their ID, but I am finding it difficult to add their name. Below, I have attached my Chat mongoose model, as well as my route to add a user to a chat. Also, I have attached my User mongoose model. Any help is greatly appreciated. Thank you!
Chat model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ChatSchema = new Schema({
title: {
type: String,
required: true
},
password: {
type: String,
required: true
},
creator: {
type: Schema.Types.ObjectId,
ref: 'user'
},
users: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
name: {
type: String,
required: true
}
}
],
code: {
type: String,
required: true
},
posts: [
{
text: {
type: String,
required: true
},
title: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Chat = mongoose.model('chat', ChatSchema);
route to add user to chat:
// #route Put api/chats
// #desc Add a user to a chat
// #access Private
router.put('/', [auth,
[
check(
'code',
'Please include the code for the chat')
.not()
.isEmpty(),
check(
'password',
'Please include the password for the chat'
).not()
.isEmpty()
]
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const chat = await Chat.findOne({ code: req.body.code });
//const user = await User.findOne({ user: req.user.id });
if (!chat) {
return res.status(400).json({ msg: 'Invalid Credentials' });
}
// Check if the chat has already been joined by the user
if (chat.users.filter(member => member.user.toString() === req.user.id).length > 0) {
return res.status(400).json({ msg: 'Chat already joined' });
}
//console.log(chat.password);
const isMatch = await bcrypt.compare(req.body.password, chat.password);
if (!isMatch) {
return res.status(400).json({ errors: [{ msg: 'Invalid Credentials' }] });
}
const newUser = {
user: req.user.id,
text: req.user.name
}
chat.users.unshift(newUser);
await chat.save();
res.json(chat.users);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
User model:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model('user', UserSchema);
in this part, it seems you are assigning the user's name to a text property, which I think it should be name not text.
const newUser = {
user: req.user.id,
text: req.user.name
}
The code should be:
const newUser = {
user: req.user.id,
name: req.user.name //Property should be name
}
I hope this works!
I am working on an eCommerce application, and I am trying to save users in my database but when I hit the API in the postmen then instead of :
res.json({
name: user.name,
email: user.email,
id: user._id
});
});
**instead of this code following code is running
user.save((err, user) => {
if (err) {
return res.status(400).json({
err: "NOT able to save user in DB"
});
}
//the complete code of my "auth.js" file is as following:
const User = require("../models/user");
exports.signup = (req, res) => {
const user = new User(req.body);
user.save((err, user) => {
if (err) {
return res.status(400).json({
err: "NOT able to save user in DB"
});
}
res.json({
name: user.name,
email: user.email,
id: user._id
});
});
};
exports.signout = (req, res) => {
res.json({
message: "User signout"
});
};
///and the complete code of my user model file is as following:
var mongoose = require("mongoose");
const crypto = require("crypto");
const uuidv1 = require("uuid/v1");
var userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
maxlength: 32,
trim: true
},
lastname: {
type: String,
maxlength: 32,
trim: true
},
email: {
type: String,
trim: true,
required: true,
unique: true
},
userinfo: {
type: String,
trim: true
},
encry_password: {
type: String,
required: true
},
salt: String,
role: {
type: Number,
default: 0
},
purchases: {
type: Array,
default: []
}
},
{ timestamps: true }
);
userSchema
.virtual("password")
.set(function(password) {
this._password = password;
this.salt = uuidv1();
this.encry_password = this.securePassword(password);
})
.get(function() {
return this._password;
});
userSchema.methods = {
autheticate: function(plainpassword) {
return this.securePassword(plainpassword) === this.encry_password;
},
securePassword: function(plainpassword) {
if (!plainpassword) return "";
try {
return crypto
.createHmac("sha256", this.salt)
.update(plainpassword)
.digest("hex");
} catch (err) {
return "";
}
}
};
module.exports = mongoose.model("User", userSchema);
SO please anyone tell me how to solve this problem while hiting this code to api mongo shell is also opend and mean while i also keep ROBO3T connected.
I'm trying to create a route where it takes in a parameter for a username and then displays that users information. Only thing is, the username is in the user schema from when the user signs up. The profile schema references the user schema. How do I use the username parameter in the findOne call to display the users profile data?
User schema:
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model("users", UserSchema);
Profile schema:
const ProfileSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "users"
},
name: {
type: String
},
image: {
type: String
},
bio: {
type: String
},
location: {
type: String
},
website: {
type: String
},
social: {
youtube: {
type: String
},
facebook: {
type: String
},
instagram: {
type: String
},
twitter: {
type: String
}
}
});
module.exports = User = mongoose.model("profile", ProfileSchema);
Route:
router.get("/user/:username", (req, res) => {
const errors = {};
Profile.findOne({ user: req.params.user.username })
.populate("user", "username")
.then(profile => {
if (!profile) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile);
})
.catch(err => res.status(404).json(err));
});
Please try this :
router.get("/user/:username", async (req, res) => {
const errors = {};
try {
const profile = await User.aggregate([
{ $match: { username: req.params.username } },
{ $lookup: { from: "profile", localField: "_id", foreignField: "user", as: "userProfile" } },
{ $project: { userProfile: { $arrayElemAt: ["$userProfile", 0] }, username: 1, _id:0 } }
]).exec();
if (!profile.length) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile[0]);
} catch (error) {
console.log('Error in retrieving user from DB ::', error);
return res.status(404);
}
})
Try using aggregate, firstly you check-in user table for getting details of a specific username then fetch the profile details as below using lookup, if no profile found after unwind the document will not be fetched and you can check on aggregate result's length as aggregate always return an array in result :
User.aggregate([
{$match:{ username: req.params.user.username }},
{$lookup:{from:"profile",localField:"_id",foreignField:"userId",as:"profileData"}},
{$unwind:"$profileData"},
{$project:{profileData:1,username:1}}
{$limit:1}
])
.then(profile => {
if (!profile.length) {
errors.noprofile = "There is no profile for this user";
return res.status(404).json(errors);
}
res.json(profile[0]);
})
You can do it in 2 steps.
Look for users containing username in userSchema, get it's id.
Then in promise, use that id to, look for profileSchema contains.
router.get("/user/:username", (req, res) => {
users.findOne({ username: req.params.username }).then(_user=>{
profile.findOne({ user: _user._id }).populate('user').then(_profile => {
res.json(_profile);
})
})
});
This code will look for username in userSchema and look for userSchema's id in profileSchema then returns profileSchema populated with user.