How to push unique data to an array in MongoDb document with Mongoose? - node.js

I want to write a logic for course enrollment for my app. When user click on Enroll button the api executes the code and add the course to the logged in user's document in MongoDB user collection.
The user can enroll to many courses but not the same one again and again. I want the course title and slug to be unique.
Here is the code of CourseSchema:
import mongoose from "mongoose";
const RegisterCourseSchema = new mongoose.Schema({
title: {
type: String,
required: true,
unique: true,
},
slug: {
type: String,
required: true,
unique: true,
},
});
export default mongoose.models.Course ||
mongoose.model("Course", RegisterCourseSchema);
I am doing as follow:
const { userId, title, slug } = req.body;
let course = new Course({
title: title,
slug: slug,
});
const result = await User.findByIdAndUpdate(
{ _id: userId },
{
$addToSet: {
courses: [{title: req.body.title, slug: req.body.slug}],
},
},
{ strict: false }
);
await result.save();
registerCourse();
res.status(200).json("success true");
This code runs and add the course to the logged in user document. See the picture below.
The problem in this code is that whenever this code is run this will add the duplicate the data. I actually want that If some one pass the same title and the same slug again and again then this will not be added to the MongoDB database.

Related

MongoDB populate() to dynamically load/migrate data not working

I am building an app in which the user adds and deletes objects (Pic) in an array('pics') after registering, but not sure how to dynamically load or populate('pics') to userSchema to automatically render. The user registers on the app with that array originally empty ('pics' = zero), and will create or delete those objects thereafter when logged in.
Following the documentation, I used "await User.find().populate('pics');" to migrate data in index method, but did not work.
Besides, should I include 'pics' key at store method, or userSchema 'pics' should be enough?
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
const User = mongoose.model('User', userSchema);
const Pic = mongoose.model('Pic', picSchema)
async index(req, res, next) {
const users = await User.find().populate('pics');
res.status(200).json(
devs
);
},
async store(req, res) {
try {
const { name } = req.body;
let user = await User.create({
name,
pics
})
// await user.populate('pics').execPopulate();
res.send({ user })
}
} catch (error) {
res.status(400).send(error);
}
},
I worked a time ago with MongoDB and NodeJS. I think that you have a problem with the definitions. Also, you can read the documentation https://mongoosejs.com/docs/populate.html
You need to define the _id for collections (Schema).
const userSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
So, when you create a new User, the _id is completed (you can generate it or it can be generated automatically) and ignore the field pics. When you create a Pic, you need to read the _id of the User and assigned as 'dev', something like:
let pic = new Pic({
thumbnail: '', description: '',
dev: yourUser._id
});
Using this way to create documents, you can use the populate function.

How to insert a user's id into a separate collection in Mongodb?

I have two models, one that holds the user and one that holds their text(Blog). I simply want to append the user's id every time they post their text so I can later go ahead and query for my own use.
This is what I have tried doing but nothing happens. Do we need to use req.body.user_id? Why is req.session.user not working(not being added along with the new instance of Blog on save) when I intentionally made it carry the user's id
router.route("/blog/add").post((req, res) => {
// Retrieve the uid form the user
// Save uid to the db along with the whole Blog instance
let blog = new Blog({
user_blog: req.body.user_blog,
createdAt: req.body.createdAt,
date: req.body.date,
user_id: req.session.user //Not working even though it holds the id already
});
blog.save()
.then(blog => {
res.status(200).json({
message: "Blog saved succeccfully"
});
})
.catch(err => {
res.status(400).send("Failed to save users blog");
});
});
Schema Blog
let Blog = new Schema({
user_blog: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
date: {
type: String,
default: moment(new Date()).format("MMM Do YY, HH:mm")
},
user_id: {
type: mongoose.Schema.Types.ObjectId // This will be the users own id
}
}, { collection: "users_blogs" });
The user_id is not being appended, why?

How do I get the logged-in User ID when creating a post request for that user without using req.params.id?

Let's say I have an API with a /posts endpoint. Each post in my Mongoose schema has a reference to the user that created it, and each user has an array of references to the posts they created.
When posting as a logged-in user, in order to save that reference I need to send the current logged-in user ID along with the content of the post to the /posts endpoint. I would prefer not to do so through some nested query like /users/:id/posts and then send req.params.id. I would like to post directly to /posts but send the user.id in the request somehow.
User model:
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}]
});
Posts model:
const PostSchema = new Schema({
content: {
type: String,
required: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
Create new post (need a way to get the user ID since it won't actually be in req.params)
exports.createPost = async function(req, res, next) {
try {
const { content } = req.body; // ideally would get user ID from here
const post = await db.Post.create({
content,
user: req.params.id
});
const postUser = await db.User.findById(req.params.id);
postUser.posts.push(post.id);
await postUser.save();
const newPost = await db.Post.findById(post.id);
const {id, created} = newPost;
return res.status(201).json({
id,
content,
created
})
}
catch(err) {
return next(err);
}
}
I know I'm probably missing something obvious, but I appreciate any suggestions.

MongoDB Creating document and on success create another document

I am working on application using Node.js and MongoDB. I have a particular use case wherein I create a new user and on success add the user's ObjectId into another collection called 'cities' by fetching the user's city if not existing or create a new one and append User's ObjectId to Subscriber's List field of the city document.
The Schemas look like below:
CitiesSchema:
var CitiesSchema = new Schema({
City:{
type: String
},
SubscribersList: [{type: Schema.ObjectId}]
});
User Schema:
var UsersSchema = new Schema({
emailId: {
type: String,
required: 'Mandatory field'
},
city: {
type: String
},
subscribedOn: {
type: Date,
default: Date.now
},
lastEmailSent: {
type: Date,
default: null
},
isActive: {
type: Boolean,
default: true
}
});
Please let me know how I can tackle this in the cleanest way possible or is there any design pattern I need to follow ?
You can use the then notation to continue processing after you have created your User. Like this
UserSchema.create({
emailId: 'email#exmaple.com',
city: 'Rome'
})
.then(user => {
// For example if you want to push to the city of the user
CityScema.update({
City: user.city
}, {
$push: {
SubscribersList: user._id
}
}).then(() => {
res.sendStatus(200);
}).catch(err => res.status(500).send(err));
}).catch(err => {
// Handle your errors here
console.error(err);
});
Make sure you check the Mongoose docs on Models for more information

Add Data to MongoDB Models At Different Times

I have a pretty good understanding of mongdoDB with mongoose, but this one aspect of it has been confusing me for a while now. I have a user.js model with a username, password, etc (all the basic user stuff). This data is added when a user registers for an account. But each user also has more data linked to it that IS NOT created or added at the time of registering.
This is my model:
// User Schema
const UserSchema = new Schema({
// PERSONAL USER INFO
username: {
type: String,
index: true
},
email: {
type: String
},
password: {
type: String
},
// INSTAGRAM ACCOUNT INFORMATION
ig_username: {
type: String
},
ig_password: {
type: String
},
story_price: {
type: Number
},
fullpost_price: {
type: Number
},
halfpost_price: {
type: Number
},
leads: [{
title: { type: String }
}]
});
// EXPORTS
const User = module.exports = mongoose.model('user', UserSchema);
All the field except "leads" are created at the time of registering. But I want to fill the Leads field using another form. I've tried the .update(), .save(), $set, $push, and all kinds of methods, but I cannot get it to work.
Most solutions that I have found use var user = new User({...}) to create a new user and then use .save() after adding the additional data. But this seems wrong since the user has already been created and I am just trying to add data to an additional field.
I think I'm just glossing over something basic, but if there is a way to do this I would be glad to hear it. Thanks!
I would create a sub-schema for leads
// Create a sub-schema for leads
const leadsSubSchema = new Schema({
title: {
type: String,
},
});
// Create a schema for user
const UserSchema = new Schema({
username: {
type: String,
index: true
},
// ...
leads: [leadsSubSchema]
});
// EXPORTS
const User = module.exports = mongoose.model('user', UserSchema);
Then for the update
User.update({
_id: user_id,
}, {
$push: {
leads: lead_to_add,
},
});

Resources