How can I get a field alone from a model to show - node.js

I have 2 models, a user model, and a follow model that handles the following of users. I would like to be able to get the followers to users in a get request. How can I get this?
Below is the user model
const userSchema = new mongoose.Schema({
fullname: {
type: String,
required: true,
trim: true,
lowercase: true
},
username: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
minlength: 7,
trim: true,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error('Passwoed cannot contain "password"')
}
}
},
isActive: {
type: Boolean,
required: false,
default: true
}
})
Here is the Follow model that handles the following of users. When a logged-in user follows another user, we set the followedBy to the logged-in user and the user to the user that is getting followed.
const followSchema = new mongoose.Schema({
// the logged in user who will be trying to follow someone will be added to "followedBy"
// the user who is getting followed will be added to "user"
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
followedBy: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Showcase'
}
}, {
timestamps: true
})
Below is the post request where I would like to get a list of object id's that follows a user (passed through the id in the parameter)
// Get a users followers
router.get('/api/:id/followers', async (req, res) => {
try {
const followers = await Follow.find({
user: req.params.id
})
console.log(followers.followedBy)
res.status(200).send(followers)
} catch (e) {
res.status(500).send()
}
})
How can I get the object id's of followedBy?

You could put the followers and following actions into the user schema as attributes
const userSchema = new mongoose.Schema({
fullname: {
type: String,
required: true,
trim: true,
lowercase: true
},
username: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
minlength: 7,
trim: true,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error('Passwoed cannot contain "password"')
}
}
},
isActive: {
type: Boolean,
required: false,
default: true
},
following: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
followers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
]
});
const User = mongoose.model('User', userSchema)
if you still want to stick to having a Follow model here's a solution you might like
const followSchema = new mongoose.Schema({
//user below is the user that is being followed
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},{
timestamps: true
});
const Follow = mongoose.model('Follow', followSchema);
const userSchema = new mongoose.Schema({
fullname: {
type: String,
required: true,
trim: true,
lowercase: true
},
username: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
minlength: 7,
trim: true,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error('Passwoed cannot contain "password"')
}
}
},
isActive: {
type: Boolean,
required: false,
default: true
},
following: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Follow",
},
],
followers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Follow",
},
]
});
const User = mongoose.model('User', userSchema);
we can have a follow route in our API or server:
app.post('/follow/:user_id', (req, res) => {
//perform follow code
})
When user A clicks on a button to follow user B, we pass in user B's user_id as a parameter to our API like this
http://localhost:54757/follow/userB_id
We already know we're in user A's account because he's the one clicking on the follow button, so we can just get user A's user Id using an auth token that we must have given him upon signup/signin
In our API we create 2 new objects from the Follow model using the follow route
app.post('/follow/:user_id', (req, res) => {
//push this one into user B's "followers" array and save user B
const new_follow1 = new Follow({
user: userA_id //id gotten from session or auth token
});
//push this one into user A's "following" array and save user A
const new_follow2 = new Follow({
user: req.params.userB_id //id gotten from request parameters req.params
});
})
then finally save the two new Follows
new_follow1.save();
new_follow2.save()

Related

remove referencing objects on deletion from array in MongoDB

I have 2 schemas User and Restaurant, and user has an array of restaurants, am trying to reach when deleting the restaurant delete its reference from user automatically, am trying to reach it with the model.pre('remove')..but when I delete a restaurant the reference id it still exist in User.
Here is my User Schema:
const userSchema = new Schema(
{
email: {
type: String,
trim: true,
// required: true,
unique: true,
},
password: {
type: String,
// required: true,
min: 5,
},
stripeCustomerId: {
type: String,
// unique: true,
},
linkedAffiliateUser: {
type: String, //mongoose.Schema.Types.ObjectId,
},
restaurants: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
},
],
role: {
roleId: { type: Number, minlength: 1, maxlength: 1, required: true },
roleName: { type: String, trim: true, required: true },
},
// seperated schema
},
{ timestamps: true }
);
export default mongoose.model("User", userSchema);
and here is my Restaurant Schema:
const restaurantSchema = new Schema({
restaurantOwner: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
Name: {
type: String,
trim: true,
},
server: { type: mongoose.Schema.Types.ObjectId, ref: "ServerUser" },
restaurantLinkAccess: {
type: String,
required: true,
trim: true,
unique: true,
},
});
restaurantSchema.pre("remove", function (next) {
this.model("User")
.update(
{ restaurantSchema: this },
{ $pull: { comments: this._id } },
{ multi: true }
)
.exec(next);
});
export default mongoose.model("Restaurant", restaurantSchema);
I also tried to solve it like this:
restaurantSchema.pre("remove", function (next) {
this.model("User").remove({ $pull: { restaurants: this._id } }, next);
});
Please help.

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);
}
})

How to get objectId of user in mongoose

I am currently working on a user registration setup. In the user model, I have defined apiKey as a property of the user and I want to set it equal to the user object Id. How can I do this ? Here is my code for the model :
const userScheama = new mongoose.Schema(
{
email: {
type: String,
trim: true,
required: true,
unique: true,
lowercase: true
},
name: {
type: String,
trim: true,
required: true
},
hashed_password: {
type: String,
required: true
},
apiKey:{
type: String,
required: false,
},
plan:{
type: String,
required: false
},
salt: String,
role: {
type: String,
default: 'subscriber'
},
resetPasswordLink: {
data: String,
default: ''
}
},
{
timestamps: true
}
);
You can use mongoose hooks here. First you need to update your apiKey to apiKey: {type:Schema.Types.ObjectId required: false }, and then add the below code to your model file
userScheama.pre('save', async function (next) {
this.apiKey = this._id;
next();
});

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 } },
});

Sub-schema properties are not updated mongoose

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!

Resources