How can i populate multiple paths in my DB? - node.js

I want different values from the nested schema. How can I populate them so that every field is showing me its nested data and not the object ID?
I'm using MongoDB and node/express.
This is my postDB where the post schema is defined:
const mongoose = require('mongoose');
var postSchema = new mongoose.Schema({
title: {
type:String,
required:true
},
body: {
type:String,
required:true
},
comments:[{
type: mongoose.Schema.Types.ObjectId,
ref: "comment"
}],
category:{
type:String,
required:true
},
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
}
},{timestamps : true}
)
module.exports = mongoose.model('postData', postSchema);
This is my commentDB which is referenced from the postDB:
const mongoose = require('mongoose');
// Using the Schema constructor, create a new CommentSchema object
// This is similar to a Sequelize model
var CommentSchema = new mongoose.Schema({
// `body` is of type String
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
body: String
},{timestamps : true});
var Comment = mongoose.model("comment", CommentSchema);
module.exports = Comment;
This is how I'm trying to populate:
router.get('/READ', (req,res)=>{
posts.find({}, function (err, post) {
if (err) {
console.log(err);
}else{
res.json({post})
}
}
)
.populate([{path:'creator'}, {path:'comments'}])
})
However the results i get from this does not populate every object ID.
For example:
{
"comments": [
{
"_id": "5f8d91d8f8550044f0f755c8",
"creator": "5f84e5b1d893ac42dcc9cb78",
"body": "This looks cool",
"createdAt": "2020-10-19T13:17:12.323Z",
"updatedAt": "2020-10-19T13:17:12.323Z",
"__v": 0
},
{
"_id": "5f8d92e82ecfbe34b8f6375b",
"creater": "5f84e5b1d893ac42dcc9cb78",
"body": "hello",
"createdAt": "2020-10-19T13:21:44.463Z",
"updatedAt": "2020-10-19T13:21:44.463Z",
"__v": 0
},
],
"_id": "5f887cef6fd7d34548a592ea",
"title": "A DESCRIPTIVE PARAGRAPH EXAMPLE",
"body": "\"The room in which I found myself was very large and lofty. The windows were ",
"category": "Finance",
"creator": {
"joined": "2020-10-15T12:14:23.888Z",
"posts": [
"5f887cef6fd7d34548a592ea",
"5f887e0d6fd7d34548a592ec",
"5f887e266fd7d34548a592ed",
"5f887e586fd7d34548a592ee",
"5f89bfccc2bebd40b07b044a",
"5f89c36e906bbb27b84af897",
"5f89c7614199d52b141ff249",
"5f89c7ea4199d52b141ff24a",
"5f8c5ab175ef762ed89eddba",
"5f8c5be2d7fac046f0021d9f"
],
"_id": "5f88481d00ed460960da90f8",
"username": "kenwaysharma",
"email": "kenwaysharma#gmail.com",
"password": "$2b$10$p3qjmdSKWIF9qAagZoqbjuG34cjOgXTe5XYER0aowwviIS65COVlu",
"__v": 0
},
"__v": 0,
"updatedAt": "2020-10-20T05:42:56.320Z"
}
Here is the userDB:
username: {
type: String,
required: [true, "Username is required!"],
unique: true,
lowercase: true,
},
email:{
type: String,
required: [true, "Email is required!"],
unique: true,
lowercase: true,
validate: [isEmail, "Please enter a valid email!"]
},
password:{
type: String,
required: [true, "Password is required!"],
minlength: [6, "Enter atleast 6 characters!"],
},
comments:[{
type: mongoose.Schema.Types.ObjectId,
ref: "comment"
}],
posts:[{
type: mongoose.Schema.Types.ObjectId,
ref: "postData"
}],
},{timestamps : true});
GET users:
router.get('/USERS', (req,res)=>{
User.find({}, function (err, user) {
if (err) {
console.log(err);
}else{
res.send(user)
}
}
).populate('comments') .populate('posts')
})
How do I get the creator data inside of comments instead of just its object ID?
Update:
I also tried selecting the creator inside comments like
.populate('comments', 'creator')
but it still gives me the creator object ID in a string.
Update 2:
I have added the code for userDB to which the commentDB and postDB references.
Also added the GET users just to see how it works in postman.

Try chaining multiple populate methods and using the exec method to pass your callback.
posts.find({})
.populate({
path: 'comments',
populate: {
path: 'creator',
model: 'user'
}
})
.populate('creator')
.exec(function (err, post) {
if (err) {
console.log(err);
}else{
res.json({post})
}
});

Related

MissingSchemaError: Schema hasn't been registered for model images

I keep getting the same error that my imageSchema hasn't been registered for ImageModel when I try to populate the posts from UserModel. But I can't figure out what's the issue. I checked the image Schema file and I don't see anything wrong. Or am I missing something else?
User model
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
min: 6,
max: 30
},
created: {
type: Date,
required: true,
default: Date.now
},
},
{
timestamps: true,
toJSON: {
virtuals: true
}
},
);
userSchema.virtual("posts", {
ref: "ImageModel",
foreignField: 'userId',
localField: '_id'
});
module.exports = mongoose.model('users', userSchema);
Image model
const imageSchema = new mongoose.Schema({
caption: {
type: String,
},
timeCreated: {
type: Date,
default: () => Date.now(),
},
img: {
type: String,
default: 'placeholder.jpg',
},
});
module.exports = mongoose.model("imagesPosts", imageSchema);
model routes
const UserModel = require("../models/User");
const ImageModel = require("../models/Image");
This is the code I'm working on to populate the posts from the User model, but I'm not sure if I'm doing it correctly or not.
const userId = req.user.id;
try {
const result = await UserModel.findById(userId).populate("posts");
console.log("\n\nPopulate result: " + result + "\n\n");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong, check logs");
}
**Desired output: **
{
"_id": "5e3a885ec511414a3c37a78c",
"username": "Johm",
"email": "john#head.dev",
"password": "123123",
"__v": 0,
"posts": [
{
"_id": "5e3a88e2c511414a3c37a78d",
"caption": "caption one",
"img": "1661309774553spaghetti.jpg",
"userId": "5e3a885ec511414a3c37a78c",
"created": "2020-02-05T09:20:49.754Z",
"__v": 0
},
{
"_id": "5e3a88f1c511414a3c37a78e",
"caption": "caption two",
"img": "1661309774553spaghetti.jpg",
"userId": "5e3a885ec511414a3c37a78c",
"created": "2020-02-05T09:20:49.754Z",
"__v": 0
}
],
}
Declare your posts field as a ref in userSchema:
const userSchema = new mongoose.Schema(
{
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'imagesPosts',
},
],
...
);
You should be able to populate it with:
await UserModel.findById(userId).populate("posts").exec();

Mongoose update subdocument

I have some posts documents which contains an array of ids of comments. I am trying to update a particular comment based on the post and the comment id and not sure how to go about it. I have tried to use the $set command but I think I missed something and It doesn't work. What I have tried doing.
async function updateComment(req, res){
try{
const post = await PostsModel.findOneAndUpdate(
{"postID": req.params.id, "comments.id": req.params.commentID},
{"$set": {
"comments.$": req.body
}}
).populate("comments");
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}
The structure and schema of the document:
{
"_id": "62b2c3d0e88f58ddd1135bc7",
"title": "aaaa",
"content": "check it out",
"createdAt": "2022-06-22T07:23:34.525Z",
"comments": [
"62b2fe23b15d50b496149128"
],
"postID": 1
}
The schema for both the post and comment:
const CommentSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
content:{
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
})
const PostsSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});

How to get model data from nested object

little bit stuck with mongoose. I want to get all users projects where he's added. Tried few options, but in all of them I receive an empty array. So the main question is it possible somehow to find all project by filtering/finding the Project model?
This is how looks my default response to understand what I'm looking for:
{
"_id": "61a8bc4e8e24f10ac7a7288d",
"name": "Random project",
"description": "Random project desc",
"maxWorkingEmployees": 5,
"status": "Paused",
"createdBy": {
"_id": "61a66578f2dabf7555bcf4ab",
"email": "Henrikas#furniture1.eu",
"role": "Owner"
},
"currentlyWorkingEmployees": [
{
"username": "Ema",
"role": "Employee",
"_id": "61a8e0423140ecce769dc971"
}
],
"createdAt": "2021-12-02T12:30:06.461Z",
"updatedAt": "2021-12-02T15:11:51.361Z",
"__v": 0
}
Project model:
const mongoose = require('mongoose');
const SingleUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
role: {
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);
Here's my controller and my first try:
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.find({
currentlyWorkingEmployees: { _id: userId },
});
res.json({projects});
};
Second shot after reading some articles
const getMyProjects = async (req, res) => {
const userId = req.user.userId;
const projects = await Project.aggregate([
{
$match: {
currentlyWorkingEmployees: { _id: userId },
},
},
]);
};
As I said in the comment you can do it accessing to the internal object of the schema with an string accessing to it child object.
Project.find({'currentlyWorkingEmployees._id': userId})

get data into schema by id in mongoose

i have two schema i would like to get some info from another schema for example (firstName, lastName) from the userSchema by id that i would provide when adding new comment on the CommentsSchema
const CommentsSchema = new mongoose.Schema({
userId: {
type: String,
required: true
},
commentText: {
type: String,
required: true
},
time: {
type: Date,
default: Date.now
}
});
const UserSchema = new mongoose.Schema({
userName: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
}
});
You can use mongoose populate to get data from a referenced collection.
First you need to change comments schema to set up a reference to the User model.
You may need to change ref value, if you used a different user model name when you applied mongoose.model("User", UserSchema).
const CommentsSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
commentText: {
type: String,
required: true
},
time: {
type: Date,
default: Date.now
}
});
Let's say you have this user in users collection:
{
"_id": "5e312d5cab2e5028b8865be3",
"userName": "Mongoose",
"firstName": "Buk",
"lastName": "Lau",
"__v": 0
}
And this comment from this user:
{
"_id": "5e312d9cab2e5028b8865be4",
"userId": "5e312d5cab2e5028b8865be3",
"commentText": "this is a comment",
"time": "2020-01-29T07:00:44.126Z",
"__v": 0
}
Now you can access the user info from comment like this:
router.get("/comments/:id", async (req, res) => {
const result = await Comment.findById(req.params.id).populate("userId");
res.send(result);
});
The result will be like this:
{
"_id": "5e312d9cab2e5028b8865be4",
"userId": {
"_id": "5e312d5cab2e5028b8865be3",
"userName": "Mongoose",
"firstName": "Buk",
"lastName": "Lau",
"__v": 0
},
"commentText": "this is a comment",
"time": "2020-01-29T07:00:44.126Z",
"__v": 0
}

mongoose add array of ids to a object

i'm trying to save a group with references to users and ranks. users and ranks is arrays of id's. However when i make a post request it seem to say that Group validation failed. What am i doing wrong with my references?
router.post('/:users/:game/:ranks/:age/:quantity/:usercount', function(req, res, next) {
var params = req.params;
var ranks = params.ranks.split(',');
var users = params.users.split(',');
var group = new Group({
users: users,
game: params.game,
ranks: ranks,
quantity: params.quantity,
age_above: params.age,
userCount: params.usercount
});
group.save(function(err, object) {
if (err) {
res.send(err);
} else {
User.findByIdAndUpdate(params.id, {$set:{group:object.id}}, {new: true}, function(err, doc){
if(err){
res.send(err);
} else {
res.send(doc);
}
}).populate('group');
}
});
});
User schema
var userSchema = new Schema({
_id: {
type: SchemaTypes.Long,
required: true,
unique: true,
index: {unique: true}
},
name: String,
birthday: Date,
country: String,
image: String,
group: { type: Schema.Types.ObjectId, ref: 'Group'},
games: [{
game: { type: Schema.Types.ObjectId, ref: 'Game'},
rank: { type: Schema.Types.ObjectId, ref: 'Ladder'},
userName: String
}],
friends: [{ type: Schema.Types.ObjectId, ref: 'User' }],
created_at: Date,
updated_at: Date
});
Error message
{
"message": "Group validation failed",
"name": "ValidationError",
"errors": {
"users": {
"message": "Cast to Array failed for value \"[ '10210697939629739' ]\" at path \"users\"",
"name": "CastError",
"kind": "Array",
"value": [
"10210697939629739"
],
"path": "users",
"reason": {
"message": "Cast to ObjectId failed for value \"10210697939629739\" at path \"users\"",
"name": "CastError",
"kind": "ObjectId",
"value": "10210697939629739",
"path": "users"
}
}
}
}

Resources