Mongoose and MongoDB, how to create relation betwean two models with multiple references? - mongodb

everyone.
So I have this "blog" app where users can create posts with images.
How my app works is that it loads different posts by userID.
So I have a relation bewtean user and post by the user and post _id, however I also want to save username into the post schema and created ralation that way. Is it possible to do such thing ?
This is my User schema
import mongoose from "mongoose";
import mongooseUniqueValidator from "mongoose-unique-validator";
const Schema = mongoose.Schema;
const validator = mongooseUniqueValidator;
const user_Schema = new Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, minlength: 3 },
user_image: { type: String },
posts: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Post' }], //relation bewtean post and user
},{ timestamps: true }
);
user_Schema.plugin(validator);
export const USER: mongoose.Model<any> = mongoose.model("User", user_Schema);
And this is my Post Schema:
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const post_Schema = new Schema({
title: { type: String, required: true, },
description: { type: String, required: true, },
imageURL: { type: String },
creator_id: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
},
{ timestamps: true }
);
export const POST: mongoose.Model<any> = mongoose.model("Post", post_Schema);
However this is what I want the post to contain, I want the post to contain ID of the user who created it and the name of the user who created it.
However I do not know how to create it. So this is how I want my Post schema to look like, I want to be able to save both the user ID and username into the post.
const Schema = mongoose.Schema;
const post_Schema = new Schema({
title: { type: String, required: true, },
description: { type: String, required: true, },
imageURL: { type: String },
user: {
creator_id: { type: mongoose.Types.ObjectId, required: true, ref: 'User' }, //relation bewtean post and user
creator_name: { <soemthing here>, ref: 'User' }, //relation bewtean post and user
},
},
{ timestamps: true }
);
export const POST: mongoose.Model<any> = mongoose.model("Post", post_Schema);

If you want to retrieve the creator name using the ref is the correct approach, you just need to populate the Post documents when you are retrieving them with:
const posts = await Post.find({}).populate('creator').exec()
for (const post of posts) {
// Every post should contain the creator user properties
console.log(post.creator._id, post.creator.username)
}
Just make sure that your ref fields are of type mongoose.Schema.Types.ObjectId:
const post_Schema = new Schema(
{
title: { type: String, required: true },
description: { type: String, required: true },
imageURL: { type: String },
creator: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
},
{ timestamps: true }
);
export const POST: mongoose.Model<any> = mongoose.model('Post', post_Schema);

Related

mongoose validator not working as expected

i want to add batch,department,stream,id fields to the schema depending if usertype is “Student”,i do not understand why,but sometimes it adds the fields sometimes not.forexample if i created a user with usertype “Student” first it does not add the fields,but after that when i created a user with usertype “Teacher” or “Admin” it asks me the fields are required meaning it add the fields and this happens vice versa.why any way to fix this issue?please help guys.
what i have tried well,i have asked chatGpt but no answers i mean just the answers do not solve the issue.
here is the code
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
{
fullName: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
userType: {
type: String,
required: true,
},
phoneNumber: { type: String, required: true },
password: { type: String, required: true },
approved: { type: Boolean, default: true },
},
{
timestamps: true,
}
);
userSchema.pre("validate", function (next) {
if (this.userType === "Student") {
this.constructor.schema.add({
batch: {
type: Number,
required: true,
},
department: {
type: String,
required: true,
},
stream: {
type: String,
required: true,
},
id: { type: String, required: true }, //, unique: true
});
}
next();
});
const userModel = mongoose.model("users", userSchema);
module.exports = userModel;

Populate a property of a mongoose schema with all the data in another collection

I have a model with articles, and would like to populate an array of data with all the documents in a collection.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ArticlesSchema = new mongoose.Schema({
path: {
type: String,
required: true,
unique: true,
},
base_headline: {
type: String,
required: true,
},
intro: {
type: String,
required: true,
},
featured_image: {
type: String,
required: true,
},
author: {
type: String,
required: true,
},
platform_filter: {
type: String,
},
free_filter: {
type: String,
},
content_type: {
type: String,
required: true,
},
data: [{ type: Schema.Types.ObjectId, ref: 'DesignProducts' }],
date: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('Articles', ArticlesSchema);
The data property should be populated with all documents in the DesignProducts collection.
I tried running this but the data array is still empty:
Article.findOne({ path: slug }).populate('data').exec();
Here is what the designProducts model looks like:
const mongoose = require('mongoose');
const DesignProductsSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
},
intro: {
type: String,
required: true,
},
website: {
type: String,
required: true,
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('DesignProducts', DesignProductsSchema);
This array should be populated with all the documents in the DesignProducts collection:

Mongo does not want to delete

I use remove and deleteMany and deleteOne, with curly brackets, and without but query always shows that they were not deleted, just always.
Author.deleteMany({}) Book.deleteMany({})
Even deleteOne ({}) does not work!
const mongoose = require('mongoose')
const schema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
minlength: 4
},
born: {
type: Number,
},
})
module.exports = mongoose.model('Author', schema)
const schema = new mongoose.Schema({
title: {
type: String,
required: true,
unique: true,
minlength: 2
},
published: {
type: Number,
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Author'
},
genres: [
{ type: String}
]
})
module.exports = mongoose.model ('Book', schema)
I should have used .then or await. Only they get all documents deleted
const results = await this.Book.deleteMany({});

MongoDB: Set and get Sub Document Schema

I'm using mongoose and I have users collection shown below, but I now want to allow the user to save a number of articles, an article has a title, subtitle, and body, One user can have many articles.
How can I restructure the users collection to allow the articles to be added
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
timestamps: true,
}
);
I'm using the below to set new data to the user's collection, how do I adapt it to allow me to set and get the new articles detailed above?
const confirmed = await userModel
.findOneAndUpdate(
{ email },
{
$set: { password },
}
)
.exec();
You can set the option strict: false and add(save) new fields to your schema.
const userSchema: Schema = new Schema(
{
email: { type: String, required: true, unique: true },
fullName: { type: String, required: true },
password: { type: String, required: true },
},
{
strict: false,
timestamps: true,
}
);
Here is the docs

Mongoose populate is not a function

I want the post's creator to be a user Schema. So i have 2 Schema
post.js
const mongoose=require('mongoose');
mongoose.Promise = global.Promise;
const Schema= mongoose.Schema;
const postSchema= new Schema({
body:{ type: String, required:true, validate:bodyValidators},
createdBy: { type: Schema.Types.ObjectId,ref:'User'}, // this one
to: {type:String, default:null },
createdAt: { type:Date, default:Date.now()},
likes: { type:Number,default:0},
likedBy: { type:Array},
dislikes: { type:Number, default:0},
dislikedBy: { type:Array},
comments: [
{
comment: { type: String, validate: commentValidators},
commentator: { type: String}
}
]
});
module.exports = mongoose.model('Post',postSchema);
user.js
const mongoose=require('mongoose');
mongoose.Promise = global.Promise;
const Schema= mongoose.Schema;
const userSchema=new Schema({
email: { type: String, required: true, unique: true, lowercase: true, validate: emailValidators},
username: { type: String, required: true, unique: true, lowercase: true, validate: usernameValidators},
password: { type: String, required: true,validate: passwordValidators},
bio: { type:String,default:null},
location: {type:String, default:null},
gender: {type:String,default:null},
birthday: { type:Date,default:null},
img: { type:String, default:'Bloggy/uploads/profile/avatar.jpeg'}
});
module.exports = mongoose.model('User',userSchema);
When a user creates a new post, I save his _id into a new post object
const post= new Post({
body: req.body.body,
createdBy:user._id,
createdAt:Date.now()
});
And when i want to recover all posts with their assigned author
router.get('/allPosts',(req,res)=>{
Post.find().populate('createdBy').exec((err,posts)=>{
if(err){
res.json({success:false,message:err});
}
else{
if (!posts) {
res.json({success:false,message:"No posts found"});
}
else{
res.json({success:true,posts:posts});
}
}
}).sort({'_id':-1}); // the latest comes first
});
It doesn't work though i've followed the documentation. The error i get is TypeError: Post.find(...).populate(...).exec(...).sort is not a function
What am I doing wrong ? Am I missing something ? Maybe the fact that both models are not in the same file ?
Remove execPopulate() it might work. It worked for me.
.exec() returns a Promise and has no method called .sort().
.sort() goes before .exec() as in Post.find(...).populate(...).sort(...).exec(...)
Look at 3rd example in the documentation.