Trying to populate mongoose schemas - node.js

This issue seems to be common but the answers for it vary. I am trying to populate these two models with their data.
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.listen(4000,()=>{
console.log('server listening on port 4000')
});
mongoose.connect('mongodb://localhost:27017/testDB',{useNewUrlParser:true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify:true });
const UserSchema = new mongoose.Schema({
username: String,
})
const PostSchema = new mongoose.Schema({
content: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
}
})
const Post = mongoose.model('Post', PostSchema);
const User = mongoose.model('User', UserSchema);
const user = new User({
username: 'alex antoine',
})
const posts = new Post({
content: 'I hope this works'
})
UserSchema.virtual('Post',{
localField: '_id',
foreignField: 'author',
ref:'Post',
})
const populateUser = async(username)=>{
const user = await User.findOne({username}).populate('posts');
const userPopulated = await user.populate('Post').execPopulate();
console.log(userPopulated);
}
const save = async()=>{
user.save();
posts.save();
}
save();
populateUser('alex antoine');
The response I received from this is
Populated User {
posts: [],
_id: 60dbe989fd1ab074d0ab0541,
username: 'alex antoine',
__v: 0
}
This seems to be a common issue that a lot of people had but none of their answers seems to work for me. Thanks in advance.

You're not declaring your user's posts as a virtual field right. Your PostSchema is correct, but your UserSchema should look like this:
const UserSchema = new mongoose.Schema({
username: String
})
UserSchema.virtual('posts', {
ref: Posts,
localfield: '_id',
foreignField: 'author'
});
This way, when dealing with a user document, you can populate its posts:
user.populate('posts').execPopulate();

result User.findOne({username}).populate('posts').exec();
// At the exec() try using execPopulate()
Then at the ref add the required: true` option

Related

What is wrong with my React.js code for blog comment feature

I created a comment feature in my node.js blog application. I am using Mongodb data base. Everything works fine in postman. I can create new comments. However, I am trying to replicate the same in my client side via React.js. I think I have exhausted all my ideas. Here is the error message I keep getting each time I try to create a new comment from client side: This error is console.log from the catch(err) in backend.
undefined
CastError: Cast to ObjectId failed for value ":id" (type string) at path "_id" for model "Post"
Post Model
//creating the user models for the database
const mongoose = require("mongoose"); //import mongoose
const Schema = mongoose.Schema;
const PostSchema = new mongoose.Schema(
{
title:{
type: String,
required: true,
unique: true,
},
description:{
type: String,
required: true,
},
postPhoto:{
type: String,
required:false,
},
username:{
type: Schema.Types.ObjectId,
ref: 'User'
},
categories:{
type: Array,
},
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment',
unique: true,
}]
}, {timestamps: true},
);
//exporting this schema
module.exports = mongoose.model("Post", PostSchema); //the module name is "Post"
Comment Model
const mongoose = require("mongoose"); //import mongoose to be used
const Schema = mongoose.Schema;
const CommentSchema = new mongoose.Schema(
{
commentdescription:{
type: String,
required: true,
},
author:{
type: Schema.Types.ObjectId,
ref: 'User',
},
}, {timestamps: true}
);
//exporting this schema
module.exports = mongoose.model("Comment", CommentSchema); //the module name is "Post"
create new comment and push to post codes
//creating catergory logic
router.post("/posts/:id/comment", async (req, res) =>{
const newComment = new Comment(req.body);//we create a new comment for the database
try{
//we need to try and catch the new comment and save it
const currentPost = await Post.findByIdAndUpdate(req.params.id)//we need to find the post that has the comment via the id
currentPost.comments.push(newComment)//we need to push the comment into the post
await newComment.save();
await currentPost.save()//we saved the new post with the comment
res.status(200).json(currentPost)
}catch(err){
console.log(err)
res.status(500).json(err)
}
})
What I have written in React
const [commentdescription, setCommentDescription] = useState('')
const [postId, setPostId] = useState()
//function to create comment
const handleComment = async ()=>{
const newComment = {
_id: postId,
author: user._id,
commentdescription,
};
try{
await axios.post("/posts/:id/comment", newComment);
}catch(err){
console.log(err)
}
}
Everything works fine in postman. I know I am missing something in react.
You need to pass actual ID to that POST request url.
await axios.post(`/posts/${postId}/comment`, newComment);
When POSTing to /posts/:id/comment, your parsed value (req.params.id) will literally be :id, which cannot be casted as ObjectId.

Mongoose populate not working for nested object

Client.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const clientSchema = new mongoose.Schema(
{
name: { type: String, required: true, default: "" },
}, {
timestamps: true
}
);
module.exports = mongoose.model("Client", clientSchema);
User.js
const mongoose = require("mongoose");
var Schema = mongoose.Schema;
const userSchema = new mongoose.Schema({
name: { type: String, required: true, default: "" },
clients: [{
client: {
type: Schema.Types.ObjectId,
ref: "Client",
default: null
},
user_group: {
type: Number
default: null
}
}]
}, { timestamps: true });
module.exports = mongoose.model("User", userSchema);
auth.js (Where trying to populate Clients)
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const Client = require("../models/Client");
router.post("/users", (req, res) => {
let params = req.body;
let total_client = [];
User.findOne({
email: params.email
})
.populate({
path: "clients.client",
model: Client
})
.exec((err, user) => {
console.log(user);
res.send(user);
});
});
module.exports = router;
Please check the above code. I have given code examples of my two models user.js and client.js. In user schema, I have referenced client inside an array object. While querying user, the client is not population. Please help me to get this thing done. Thanks in advance.
The following expects you to provide a name in the json body of your post request (your example uses email which does not exist in the user model). Also, your model is already defining the ref: Client and so you can simplify your request to just include the path clients.client.
router.post("/users", async (req, res) => {
const { name } = req.body;
const user = await User.findOne({ name: name }).populate('clients.client').exec();
res.send(user);
});
Solved this problem just adding an extra parameter in module export of client.js file
module.exports = mongoose.model("Client", clientSchema, "client");

I can't handle populate in mongoose

I think it's not populating categories couse when i try log 'category' in console i get
"ReferenceError: category is not defined". For me it is like in docs but as we see it's not. Is anyone can tell me what is wrong??
//model/Category.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const CatSchema = new Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
}
});
mongoose.model("categories", CatSchema, "categories");
model/Story.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const StorySchema = new Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
category: {
type: Schema.Types.ObjectId,
ref: "categories"
}
});
mongoose.model("stories", StorySchema, "stories");
routes/stories.js
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Category = mongoose.model('categories');
const Story = mongoose.model('stories');
router.get('/add', (req, res) => {
Story.find()
.populate('category', 'title')
.then(stories => {
res.render('stories/add', {
stories: stories
});
});
});
Query.prototype.populate() returns a Query object on which you need to run .exec(), try this:
Story.find({})
.populate('category', 'title')
.exec()
.then(stories => {
res.render('stories/add', {
stories: stories
});
});
It was problem with that how I want to use it. Code is working

Mongoose Populate not populating the data

The following are two blocks of code, the first one is my Schema and the second one is my query. The Payment model is getting saved and it has the id referring to the user. Can I know where I am going wrong, is there any thing wrong with the fundamental ?
Here is my schema of User and Payment
User:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
var paymentSchema = new Schema({
amount: Number,
user: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
var userSchema = new Schema({
email: String,
payment: {
type: Schema.Types.ObjectId,
ref: 'Payment'
}
});
module.exports = mongoose.model('User', userSchema);
module.exports = mongoose.model('Payment', paymentSchema);
Here is my query which I am using to populate using promise:
User.findOne({email: req.query.email})
.populate('payment')
.select('_id payment')
.then(function(user) {
res.json(user);
});

User.findByID is not a function

I am having an issue with node + express routing. I have a routing schema by default provided in the IDE webstorms. I am not sure if I configured everything well, because I am having this error.
I can do a GET /users and POST /users properly with correct results on postman.
routes/users.js
const express = require('express');
const router = express.Router();
const _ = require('lodash');
const {ObjectID} = require('mongodb');
const {mongoose} = require('../db/mongoose')
const {User} = require('../db/models/users')
const {Project} = require('../db/models/projects')
const {Dialog} = require('../db/models/dialogs')
(...)
router.get('/users/:userid', (req, res) => {
var id = req.params.userid.toString();
if (!ObjectID.isValid(id)) {
return res.status(404).send();
}
User.findByID(id).then((user) => {
if (!user) {
return res.status(404).send();
}
res.send({user});
}).catch(() => {
res.status(404).send();
});
});
models/users.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema
// todo refactor userschema with proper validators (view udemy course)
const UserSchema = new Schema({
email: {type: String, required: true},
password: {type: String, required: true},
name: {type: String},
company: {type: String},
phone: {type: String},
projects: [{type: Schema.Types.ObjectId, ref: 'Project'}]
});
const User = mongoose.model('User', UserSchema);
module.exports = {User}
Mikey is right. Mongoose model function is findById() not findByID() - http://mongoosejs.com/docs/api.html#model_Model.findById

Resources