Sub-schema properties are not updated mongoose - node.js

little bit stuck with one issue which is related to mongoose. I have a Project schema with sub-schema(SingleUserSchema). Whenever I add a new User to this schema it saves everything and that's ok. The issue is that if I update the user, old values in schema does not update. Any ideas how to solve this case? Stuck here for a whole day already.
Schema:
const mongoose = require('mongoose');
const SingleUserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
},
role: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
});
const ProjectSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'Provide project name'],
minlength: 5,
},
description: {
type: String,
required: [true, 'Provide description about the project'],
},
maxWorkingEmployees: {
type: Number,
required: [
true,
'Provide maximum number of employees working on this project',
],
},
currentlyWorkingEmployees: [SingleUserSchema],
status: {
type: String,
enum: ['Pending', 'In progress', 'Paused', 'Delayed', 'Completed'],
default: 'Pending',
},
createdBy: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model('Project', ProjectSchema);
Controller:
const attachEmployeeToProject = async (req, res) => {
const { projectId, userId } = req.params;
const project = await Project.findOne({ _id: projectId });
const user = await User.findOne({ _id: userId });
if (!user) {
throw new NotFoundError(`User with id ${userId} does not exists`);
}
if (!project) {
throw new NotFoundError(`Project with id ${userId} does not exists`);
}
const { role, email, status } = user;
const SingleUserSchema = {
email,
role,
status,
};
let currentlyWorkingEmployees = [
...project.currentlyWorkingEmployees,
SingleUserSchema,
];
req.body.currentlyWorkingEmployees = currentlyWorkingEmployees;
const updateProject = await Project.findOneAndUpdate(
{ _id: projectId },
req.body,
{
new: true,
runValidators: true,
}
);
res.status(StatusCodes.OK).json({ updateProject });
};
Maybe I just simply need to create a reference? Tried like this and received tons of errors, also felt lost how to create n references in array.
currentlyWorkingEmployees: [
{ type: mongoose.Schema.ObjectId, ref: 'User', required: true },
],
User schema:
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: [true, 'Please provide username'],
minlength: 3,
maxlength: 50,
},
email: {
type: String,
required: [true, 'Please provide username'],
unique: true,
validate: {
validator: validator.isEmail,
message: 'Please provide valid email address',
},
},
password: {
type: String,
required: [true, 'Please provide password'],
validator: {
validate: {
validator: validator.isStrongPassword,
message: 'Please provide stronger password',
},
},
},
firstname: {
type: String,
required: [true, 'Please provide first name'],
},
lastname: {
type: String,
required: [true, 'Please provide last name'],
},
status: {
type: String,
enum: ['Working', 'Pause', 'Offline'],
default: 'Offline',
},
role: {
type: String,
enum: [
'Developer',
'Analyst',
'Designer',
'Architect',
'Project Manager',
'Owner',
'Teamleader',
'Employee',
],
default: 'Employee',
},
verificationToken: {
type: String,
},
isTokenVerified: {
type: Boolean,
default: false,
},
tokenValidationDate: {
type: Date,
default: null,
},
});

First, as far as I see you don't have a model called 'User' so that's the reason why your reference is not working.
currentlyWorkingEmployees: [
{ type: mongoose.Schema.ObjectId, ref: 'User', required: true },
]
https://mongoosejs.com/docs/populate.html
Second, you need to identify the user you want to update (based on userId) inside currentlyWorkingEmployees collection, if I understood correctly your problem.
Hope it helps!

Related

How to get a certain field of an embedded MongoDB document knowing its ObjectId

I have two collections in MongoDB database, Post and User. Each post contains the creator's ObjectId. When fetching all posts from the database, I want to add the name information, which is a field of User/creator. I tried to access the name field by post.creator.name, but it is not working.
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
creator: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
const userSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
isExpert: {
type: Boolean,
required: true,
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});
exports.getPosts = (req, res, next) => {
Post.find({}).then((posts) => {
const postsWithAuthorName = posts.map(post => {
return {
...post,
name: post.creator.name
}
})
res.status(200).json({
posts: postsWithAuthorName,
});
});
};
Try this
Post.find({}).populate('creator', 'name')
See populate doc for reference.
When you query posts, creator is just an ObjectId, so you can't just call .name on it. To make it work you need to lookup this data by using e.g. populate.

MongoDB mongoose filter with gender where user in profile is objectID

I am new in backend development.
I am trying to create profile endpoints to get all profiles with the gender of the user is either male or female.
Profile contains user as a objectID.
I want to filter profiles using users gender.
My UserSchema looks like this
const userSchema = mongoose.Schema(
{
firstname: {
type: String,
required: true,
trim: true,
},
lastname: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
unique: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Invalid email');
}
},
},
password: {
type: String,
required: true,
trim: true,
minlength: 8,
validate(value) {
if (!value.match(/\d/) || !value.match(/[a-zA-Z]/)) {
throw new Error('Password must contain at least one letter and one number');
}
},
private: true, // used by the toJSON plugin
},
role: {
type: String,
enum: roles,
default: 'user',
},
gender: {
type: String,
enum: genders,
required: true,
},
profileStatus: {
type: String,
enum: profileStatus,
default: 'inProgress',
},
isEmailVerified: {
type: Boolean,
default: false,
},
},
{
timestamps: true,
}
);
And Profile schema looks like this
const profileSchema = new Schema(
{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true, unique: true },
bio: { type: String, required: true },
profilePicUrl: {
type: String,
required: true,
},
birthdate: {
type: Date,
required: true,
},
profession: {
type: String,
required: true,
},
profileCompletion: {
type: Number,
default: 50,
min: 0,
max: 100,
},
credits: {
type: Number,
default: 2,
min: 0,
},
lastLogin: {
type: Date,
default: new Date(),
required: true,
},
},
{ timestamps: true }
);
I want to find profiles where user gender is male or female.
How can I do that?
You can create a endpoint like this and use .find() to find all the users with the gender passed by user
router.get(/user/:gender, async (req, res) => {
try {
const users = await User.find({ gender: req.params.gender }).exec();
res.status(200).json(users);
} catch (err) {
return res.status(500);
}
})

Mongoose with mongodb how to return just saved object that have full or customize property with other collection?

I need your help. I face with problem that I cant get full property or custom property that return from saved. My explain bellow :
Post model :
const postSchema = new mongoose.Schema(
{
content: {
type: String,
trim: true,
required: [true, "Post must be required"],
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
liked: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
disliked: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
imageUrl: {
type: String,
trim: true,
},
},
{ timestamps: true }
);
User model :
const userSchema = new mongoose.Schema({
name: {
type: String,
unique: true,
trim: true,
required: [true, 'Name must be required']
},
email: {
type: String,
unique: true,
trim: true,
required: [true, 'Email must be required']
},
password: {
type: String,
unique: true,
trim: true,
required: [true, 'Password must be required'],
minlength: [6, 'Password must be at least 6 characters']
},
}, {timestamps: true});
function create new Post and response Post to client :
exports.createOnePost = async (req, res, next) => {
console.log("create one");
try {
const post = await Post.create({
content: req.body.content,
author: req.user.userId,
liked: req.body.liked,
imageUrl: req.body.imgUrl,
});
res.status(200).json({
status: "success",
data: { post },
});
} catch (error) {
next(error);
}
};
After saved Post to database , I want to return full property of User and Post as well.
But I just received a Post :
{
content: 'sfdfsfd44434',
author: new ObjectId("61c1e08837d77c6187b9a746"),
liked: [],
disliked: [],
_id: new ObjectId("620c77d7574ce70b2417c1a1"),
createdAt: 2022-02-16T04:04:39.016Z,
updatedAt: 2022-02-16T04:04:39.016Z,
__v: 0
}
Hope that a solution from you guys. Thank you so much !
Since you already have the user you can just return it in your response like this:
res.status(200).json({
status: "success",
data: { post: { ...post.toObject(), author: req.user } },
});

Want to get a user who uploaded the product in the order model schema mongo db mongoose

I have a product schema in which user(who uploaded ,created the product) is there who creates a product and then there is an order , order schema has the product included , I want it to include the products uploader user . Can anyone help me to do that ? I really hope i make it clear enough it's haunting me for days and I have searched the internet
const mongoose = require('mongoose')
const orderSchema = mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true
},
city: {
type: String,
required: true
},
phoneNo: {
type: String,
required: true
},
postalCode: {
type: String,
required: true
},
country: {
type: String,
required: true
}
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product'
},
}
],
paymentInfo: {
id: {
type: String
},
status: {
type: String
}
},
paidAt: {
type: Date
},
itemsPrice: {
type: Number,
required: true,
default: 0.0
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
orderStatus: {
type: String,
required: true,
default: 'Processing'
},
deliveredAt: {
type: Date
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema)
this is my product Schema
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter product name'],
trim: true,
maxLength: [100, 'Product name cannot exceed 100 characters']
},
price: {
type: Number,
required: [true, 'Please enter product price'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0.0
},
description: {
type: String,
required: [true, 'Please enter product description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
}
],
category: {
type: String,
required: [true, 'Please select category for this product'],
enum: {
values: [
'Electronics',
'Cameras',
'Laptops',
'Accessories',
'Headphones',
'Food',
"Books",
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
message: 'Please select correct category for product'
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter product stock'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product', productSchema);
this is my user Schema
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken')
const crypto = require('crypto')
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter your name'],
maxLength: [30, 'Your name cannot exceed 30 characters']
},
email: {
type: String,
required: [true, 'Please enter your email'],
unique: true,
validate: [validator.isEmail, 'Please enter valid email address']
},
password: {
type: String,
required: [true, 'Please enter your password'],
minlength: [6, 'Your password must be longer than 6 characters'],
select: false
},
avatar: {
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
}
},
role: {
type: String,
default: 'user'
},
createdAt: {
type: Date,
default: Date.now
},
resetPasswordToken: String,
resetPasswordExpire: Date
})
// Encrypting password before saving user
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) {
next()
}
this.password = await bcrypt.hash(this.password, 10)
})
// Compare user password
userSchema.methods.comparePassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password)
}
// Return JWT token
userSchema.methods.getJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_TIME
});
}
// Generate password reset token
userSchema.methods.getResetPasswordToken = function () {
// Generate token
const resetToken = crypto.randomBytes(20).toString('hex');
// Hash and set to resetPasswordToken
this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex')
// Set token expire time
this.resetPasswordExpire = Date.now() + 30 * 60 * 1000
return resetToken
}
module.exports = mongoose.model('User', userSchema);
Order.find(any order).populate([ { path: 'orderItems.product', model: 'Order', populate: [ { path: 'user', model: 'User', select: 'name', }, ], }, ]) ` Note: you can edit it for correct paths

want to show orders only to specific product owners to which orders has been given in mongodb MERN STACK DEVELOPMENT

This is my order Schema
the person who actually starts the order , can get his SPECIFIC ORDERS, but the person who gets order to his product can not get specific orders.Which are his , i am copying a tutorial and making a product please help with that
const mongoose = require('mongoose')
const orderSchema = mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true
},
city: {
type: String,
required: true
},
phoneNo: {
type: String,
required: true
},
postalCode: {
type: String,
required: true
},
country: {
type: String,
required: true
}
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product'
}
}
],
paymentInfo: {
id: {
type: String
},
status: {
type: String
}
},
paidAt: {
type: Date
},
itemsPrice: {
type: Number,
required: true,
default: 0.0
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
orderStatus: {
type: String,
required: true,
default: 'Processing'
},
deliveredAt: {
type: Date
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema)
this is my product schema
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter product name'],
trim: true,
maxLength: [100, 'Product name cannot exceed 100 characters']
},
price: {
type: Number,
required: [true, 'Please enter product price'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0.0
},
description: {
type: String,
required: [true, 'Please enter product description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
}
],
category: {
type: String,
required: [true, 'Please select category for this product'],
enum: {
values: [
'Electronics',
'Cameras',
'Laptops',
'Accessories',
'Headphones',
'Food',
"Books",
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
message: 'Please select correct category for product'
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter product stock'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product', productSchema);
these are my order controller function
exports.myOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
res.status(200).json({
success: true,
orders
})
})
// Get all orders - ADMIN => /api/v1/admin/orders/
exports.allOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
//let totalAmount = 0;
/* orders.forEach(order => {
totalAmount += order.totalPrice
})
*/
res.status(200).json({
success: true,
// totalAmount,
orders
})
})
the user who initiate the order can see the orders which he initiated but the person to which order was given can not get specific order
I hope i make it clear enough , please help me I am a noob
For user you can use Model.find({ user: user_id });
For seller, you should use Model.find({ user: user_id, seller: seller_id })
This will match orders from the USER for the SELLER

Resources