Accessing a schema inside a schema using Express Router and MongoDG - node.js

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.

Related

How to find value inside array of object with mongoose?

I have events system with different role for each event (same user could be different role in different events).
I created collection of the users and this is the schema that i used:
const userSchema = new mongoose.Schema(
{
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
permissions: [{
eventId: { type: mongoose.Schema.Types.ObjectId, required: false, ref: 'Event' },
role: { type: String, required: false }
}]
},
{timestamps: true}
);
For check if the user is allowed to get this event I created middleware that need to check if the eventId is exist in the User collection under "permissions"
so this is the code that I was create:
const authorization = async (req, res, next) => {
try {
const eventId = req.params.id;
const token = req.headers.authorization.split(' ')[1]
const tokenDecoded = jwt.verify(token, process.env.JWT_SECRET);
const userId = tokenDecoded.id
console.log(userId)
const userPermissionCheck = await User.find({ _id: userId, 'permissions.eventId': { $in: eventId } } );
console.log(userPermissionCheck)
next();
} catch (error) {
res.status(401).json({ message: 'Auth failed.' })
}
}
My problem is that my find function in the authorization middleware is not working...
What the correct way to search key of object in array with mongoose?
thanks
It seems that you are on the right track from your code, but you do not need the $in operator. You should be able to do the following:
const userPermissionCheck = await User.find({ _id: userId, 'permissions.eventId': eventId });

Saving an item that is specific to a user schema but not able to retrieve it back - mongoose

I have creared two schemas, user and medicine.
If a user adds medicines it should show up only in his/her account.
I am able to save the medicine ids to that specific user but i'm not able to get those medicines back i.e: medicines show for all the other users as well.
Here's the code snippet that saves meds to specific user:
const {userId, medName, medDescription, dose, medType, date, time} = req.body;
try {
const newMed = new MedsSchema({
userId,
medName,
medDescription,
dose,
medType,
date,
time,
});
await newMed.save().then(() => res.send({response: 'ok'}));
const specificUser = await User.findById({_id: userId});
specificUser.medicines.push(newMed);
await specificUser.save().then(
User.findOne(specificUser)
.populate('medicines')
.exec(function (err, docs) {
if (err) return handleError(err);
console.log(docs);
}),
);
Here's the userSchema:
const userSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
medicines: [{type: mongoose.Schema.Types.ObjectId, ref: 'MedsSchema'}],
},
{
toJSON: {
virtuals: true,
},
},
);
router.get('/getMeds/:Id', (req, res) => {
console.log(req.params.Id);
MedsSchema.find({userId: req.params.Id}, function (err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
});
});
what do i add to this that will make me get only specific medicines for that specific user instead of getting all medicines?
Can you edit your first code snippet to
const { userId, medName, medDescription, dose, medType, date, time } = req.body;
try {
const user = await User.findOone({ _id: userId });
const newMed = await MedsSchema.create({
userId: user,
medName,
medDescription,
dose,
medType,
date,
time,
});
const specificUser = await User.findByIdAndUpdate({ _id: userId }, { $push: { medecines: newMed } });
return res.json({ newMed, specificUser })
};
and in the router
router.get('/getMeds/:Id', async (req, res) => {
console.log(req.params.Id);
const user = await User.findOne({ _id: req.params.Id }).populate({ path: 'medicines' })
console.log(user.medicines)
return res.json({meds: user.medicines})
});
also check the console results to see if everything is working

how to use populate method with react and node.js?

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

Mongoose: how to only populate, sort and return a nested object?

I have a User schema, with a messages array. The message array is filled by conversations id and referenced to a Conversation schema.
I want to fetch all conversations from a user, sort them by unread and then most recent messages. Finally, I must only return an array of lastMessage object.
For the moment, I have only managed to populate the whole user object.
Here is the Conversation Schema:
const conversationSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
messages: [{ message: { type: String }, authorId: { type: String } }],
lastMessage: {
authorId: { type: String },
snippet: { type: String },
read: { type: Boolean },
},
},
{ timestamps: true }
);
conversationSchema.index({ name: 1 });
module.exports = mongoose.model("Conversation", conversationSchema);
And here is my code:
router.get("/conversations", async (req, res) => {
try {
const { userId } = req.query;
const user = await User.findById({ _id: userId }).populate("messages");
.sort({ updatedAt: 1, "lastMessage.read": 1 });
return res.json({ messages: user.messages });
} catch (err) {
console.log("error", err);
return res.json({ errorType: "unread-messages-list" });
}
});
How to do this?

How can I insert data of user schema to main schema using mongoose

I am new in this and not getting how to insert child schema data to a parent schema array.:
My child schema model defined as :-
//user model
var userrSchema = new mongoose.Schema({
email : {
type: String,
required: "Email can't be empty.",
// unique: true
},
password: {
type: String,
required: "Password name can't be empty."
},
});
mongoose.model('Userr' , userrSchema);
And I have defined parent (Admin) schema as:-
//define admin schema
var adminSchema = new mongoose.Schema({
companyName : {
type: String,
required: "Company name can't be empty.",
required: false
},
admins: {
_id: mongoose.Schema.Types.ObjectId,
email : {
type: String,
required: "Email can't be empty.",
unique: true
},
password: {
type: String,
required: "Password name can't be empty."
},
users:[ userrSchema ]
}
});
mongoose.model('Admin', adminSchema);
I have defined both in same model file. I have a controller to register parent schema :-
mongoose.model('Admin', adminSchema);
const Admin = mongoose.model('Admin');
var MongoClient = require('mongodb').MongoClient;
module.exports.registerAdmin = (req, res, next) =>{
var admin = new Admin();
admin.companyName = req.body.companyName;
admin.admins = {
email : req.body.email,
password: req.body.password,
users : []
};
admin.save((err, doc) =>{
After registering admin schema from route file :- router.post('/registerAdmin' , ctrlAdmin.registerAdmin) I am getting result as:-
{
"admins": {
"email": "xyz#ing.com",
"password": "$2a$10$juGvica8UTqtmyywnWQuKOo9KpqX9JeFfqy1n6GR4xDL2GMLM0hze",
"users": []
},
"_id": "5cf8b54e66b45740ae68feac",
"companyName": "ABC"
"__v": 0
}
So how will I register child schema and push the details it into the parent schema users key ?? Please help . I am new in this and not getting a single idea how to insert child schema data.
EDIT:- Updated save function with admin auth
Created controller for child schema but after running the url nothing is happening:
module.exports.registerUserr = (req, res, next) =>{
var userr = new Userr();
userr.email = req.body.email,
userr.password = req.body.password,
userr.firstName = req.body.firstName,
userr.lastName = req.body.lastName,
userr.phoneNumber = req.body.phoneNumber,
userr.role = "user",
userr.verified = "false"
userr.save((err, doc) =>{
if(!err){
if(req.userData.role2 === 'admin') {
console.log("saving successful");
res.send(doc);
Admin.findOneAndUpdate({ _id: req.userData.userId },{ admins : { $push: { users: doc }}},
function (error, success) {
if (error) {
console.log(error);
}
console.log(success);
});
}
}
});
and in route router.post('/registerUserr' ,checkAuth, ctrlUserr.registerUserr);
Try replacing the save function with this
userr.save((err, doc) => {
if (!err) {
res.send(doc);
Admin.findOneAndUpdate(
{ _id: req.body.id },
{ admins: { $push: { users: userr }}},
function (error, success) {
if (error) {
console.log(error);
}
console.log(success);
}
});
}
}

Resources