Mongoose populate is not a function - mongodb

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.

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;

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

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

Subdocument not being saved in its own collection - Mongoose

I found this on the documentation for mongoose:
Subdocuments have save and validate middleware just like top-level
documents. Calling save() on the parent document triggers the save()
middleware for all its subdocuments, and the same for validate()
middleware.
But that hasn't been working for me. when I call save on my parent, the subdocument doesn't get created in its own collection. Here's my code:
Cart Model
const mongoose = require("mongoose");
const cartSchema = new mongoose.Schema({
numOfSessions: {
type: Number,
required: true
},
status:{
type: String,
enum: ["completed", "active", "deleted"],
required: true
}
}, { timestamps: true, versionKey: false });
const Cart = mongoose.model('shoppingCart', cartSchema);
module.exports = Cart;
User Model
const mongoose = require("mongoose");
const Cart = require("./xxxx").schema
const Schema = mongoose.Schema;
const userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true
},
shoppingCarts: [ Cart ]
}, { timestamps: true, versionKey: false });
const User = mongoose.model('user', userSchema);
module.exports = User;
Server Side
const new_user = new User({
firstName: req.body.firstname,
lastName: req.body.lastname,
username: req.body.username,
phoneNum: req.body.phone,
userType: req.body.userType,
email: req.body.email,
password: hashedPassword
});
new_user.shoppingCarts.push(new_cart);
console.log('pushed')
new_cart.save(); //If i take out this line, this subdocument doesn't get saved
new_user.save()
.then((result) => {
console.log(result);
});
To save the subdocument, I'm having to call save on it them well. Is this how it's supposed to be? Thx :D

retrieving array data in mongodb which match id

Below is the schema. i want to get the answers as per matched qid, but i am getting all the answers in the answers array. i have tried almost all the queries but not able to understand why is this happening, if you could give link to other article that will be helpful too.
const id = req.params.id;
Channel.findOne({answer: {qid: {$in: [id]}}})
.then(result => {
console.log(result);
// let userAnswer;
// userAnswer = result.answer.map(i => {
// return {userId: i.userId , userName: i.userId.name, answer: i.answer}
// });
// res.json({ans: userAnswer, question: result.content});
})
.catch(err => {
console.log(err);
});
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const channelSchema = new Schema({
name: {
type: String,
required: true
},
category: {
type: String,
required: true
},
creator: {
type: String,
required: true
},
subscribers: [{type: mongoose.Types.ObjectId, required: true, ref: 'User'}],
content: {
question: [{
title: {type: String, required: true},
userId: {type: mongoose.Types.ObjectId, required: true, ref: 'User'}
}]
},
answer: [{
answer: {type: String, required: true},
qid: {type: mongoose.Types.ObjectId, required: true},
userId: {type: mongoose.Types.ObjectId, required: true, ref: 'User'}
}]
});
const model = mongoose.model('Channel', channelSchema);
module.exports = model;
const id = req.params.id;
return Channel.findOne({answer: {qid: {$in: [id]}}})
.then(snapshot => {
const results = [];
snapshot.forEach(doc => {
results.push({
id: doc.id,
data: doc.data()
});
});
return results;
})
})
.catch(err => {
console.log(err);
});
This is the way when you are going to fetch one array record. Not tested, only to show you how to get single record from collection

User is not a constructor

im getting error: User is not a constructor when trying to add new document to my database. before I used mongoose.model without the Schema method and it worked great but I had to add validator and it needs this syntax and since then I can't make it work
CODE:
var UserSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, index: true, unique: true, required: true },
password: { type: String, required: true }
});
UserSchema.plugin(uniqueValidator);
let User = mongoose.model("user", UserSchema);
module.exports = User;
router.post('/', (req, res) => {
var user = new User({
username: req.body.username,
email: req.body.email,
password: req.body.password
});
// save the user
user.save(function (err) {
if (err) {
console.log('Error in Saving user: ' + err);
throw err;
}
console.log('User Registration succesful');
// return done(null, userData);
res.status(200).send({user: user})
});
});
mongoose.Schema is a constructor, so you need to call it with "new":
var UserSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, index: true, unique: true, required: true },
password: { type: String, required: true }
});
ok I fixed my issue instead of
module.exports = User;
I had to do:
module.exports = {User};