Unable to populate nested schema reference in Mongoose - node.js

I have multiple Schemas and I'm trying to query the data using populate. I'm using mongoose(5.9.7) and express js.
First Schema - ProfileSchema
const ProfileSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
jobs: [
{
type: Schema.Types.ObjectId,
ref: "Job"
}
],
resumes: [
{
type: Schema.Types.ObjectId,
ref: "Resume"
}
],
name: {
type: String,
required: true
},
});
module.exports = Profile = mongoose.model("Profile", ProfileSchema);
Second Schema - Resume Schema
const ResumeSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
fileLink: { type: String, required: true },
fileName: { type: String, required: true },
description: { type: String, required: true }
});
module.exports = Resume = mongoose.model("Resume", ResumeSchema);
Route
router.get(
"/",
passport.authenticate("jwt", { session: false }),
async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.user.id
})
.populate("resumes")
.exec();
res.json(profile);
} catch (error) {
return res.status(400).json(error);
}
}
);
This returns an empty array for both resume and jobs. I have tried different variations of populate but it doesn't work. Tried deeppopulate as well. Though User gets populated fine.
EDIT: Adding resume upload route
Route
router.post(
"/upload",
passport.authenticate("jwt", { session: false }),
upload.single("resume"),
async (req, res) => {
try {
// upload to s3 code here
if (data) {
const resumeData = {
description: req.body.description,
fileName: params.Key,
fileLink: data.Location,
user: req.user.id
};
const resume = new Resume(resumeData);
const fileSavedToSchema = await resume.save();
return res.json(fileSavedToSchema);
}
} catch (error) {
console.log(error);
}
}
);
I'm able to view the resumes using a different route.

Related

Router.post an array of Object ID'S using Mongoose and NodeJs router.post

I almost have the desired functionality but it's not exactly what I wanted to approach.
I have two model schema, Control and SubControl. The SubControl is referenced in the Control model. I want to post the control model + a reference of the SubControl.
My post method:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body});
const subControlDoc = await subControl.save();
const control = new Control({...req.body});
control.subControl.push(subControlDoc._id);
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My Control Schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [{
subControlNo: {type: Mongoose.Schema.Types.String, ref: 'SubControl'}
}],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
My SubControl schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Postman:
{
"mainControl": "nn",
"controlDescription": "controldescription",
"subControl":
[
{
"subControlNo": "1-2"
},
{
"subControlNo": "1-2-1"
}
]
}
Result I'm getting:
Question: Why am I getting 3 object id's although I inserted 2 and why only the last object ID is saved in my SubControl database? I this the way to add array of object id's or not?

Post an array of referenced object id's Mongoose NodeJs

I want to be able to post several Object id's into the array,, I have two models control and subcontrol is referenced in the control model as an array. The idea is a control number might have sub control number under it
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body}); // do something to map over these items
const subControlDoc = await subControl.save();
const control = new Control({...req.body, subControl: subControlDoc._id});
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
I'm able to save one object ID of the subControl although I defined the subControl as an array in the control model. How can I insert multiple subControls ?
EDIT
I edited my solution as suggested in the answers:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body});
const subControlDoc = await subControl.save();
const control = new Control({...req.body});
control.subControl.push(subControlDoc._id);
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My postman:
{
"mainControl": "nn",
"controlDescription": "controldescription",
"subControl":
[
{
"subControlNo": "1-2"
},
{
"subControlNo": "1-2-1"
}
]
}
Control model:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [
{
type: Mongoose.Schema.Types.Mixed,
ref: 'SubControl'
}
],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
SubControl Schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Response I'm getting:
Not want I want to achieve, I want to be able to save several subControl, each subControl to be saved as an individual ObjectId rather than saving it as a String with one ObjectId

dynamic references by sending it from the route

I have been looking at the documentation and some other questions made, but I have not been able to do it, I need to consult another collection for an objectId, but these collections come dynamically in the routes.
The collections come req, as they are from many different clients
https://mongoosejs.com/docs/populate.html
//route
// example collection dynamic ssdf2451_users, ssdf2451_campus, ssdf2451_programs
router.get('/school/prueba/tipos/', async (req, res, next) => {
let users
let school
let prueba
try {
const Users = model(`ssdf2451_users`, UserSchema)
console.log(Users)
await Users.findOne({ _id: '5ef56f70d19aea6e70c82a50' })
.populate('schoolId')
.exec(function (err, usersDocuments) {
console.log(usersDocuments, err)
// handle err
prueba = usersDocuments
res.status(200).json(prueba)
})
} catch (err) {
next(err)
}
})
// Schema
import { Schema, model } from 'mongoose'
const UserSchema = new Schema({
state: {
type: Boolean,
default: false,
required: false
},
accountNumber: {
type: Number,
required: false
},
schoolId: {
type: Schema.Types.ObjectID,
required: true,
ref: 'schools'
},
campusId: {
type: Schema.Types.ObjectID,
required: true,
ref: dynamic
},
programsId: {
type: [Schema.Types.ObjectID],
required: false,
ref: dynamic
},
})
const User = model('users', UserSchema)
export { User, UserSchema }

Duplicate item returned from collection

Blog Schema:
{
body: { type: String, required: true },
title: { type: String, required: true },
published: { type: String, default: false },
date: { type: Date, default: Date.now },
user: { type: Schema.Types.ObjectId, ref: 'BlogUser' },
comments: [{ type: Schema.Types.ObjectId, ref: 'Comments' }],
likes:[{user:{ type: Schema.Types.ObjectId, ref: 'BlogUser' }}]
}
Like Route for adding a like:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
await Blog.findByIdAndUpdate(
blog_id,
{
$push: {
likes: {
user: user_id,
},
},
},
{ new: true },
(err, newBlog) => {
if (err) res.status(422).json(err);
console.log(newBlog);
res.json(newBlog);
}
);
};
Blog Route for reciveing a blog:
exports.getBlogByID = async (req, res) => {
const blog_id = req.params.blog_id;
try {
const blog = await Blog.findById(blog_id)
.populate("comments")
.populate("user");
console.log(blog);
res.json(blog);
} catch (error) {
res.status(401).json(error);
}
};
When I add a like by calling Like route from client, I get a blog with correct amount of likes i.e only 1. But when I request blog from Blog Route it returns me with two objects inside "likes" array, with both same as each other(same id too). Why am I getting such result? Mind you that I call 'Blog Route' after calling 'Like Route'.
It worked fine after I changed "like route" to this:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
const blog = await Blog.findById(blog_id);
blog.likes.unshift({ user: user_id });
await blog.save();
Blog.findById(blog_id)
.then((result) => {
res.json(result);
})
.catch((error) => {
res.status(501).json({ error });
});
};
I still don't know what's the difference between the two though.

How to pass an ObjectId into a POST request?

I am trying to make a One-To-Many relationship between two tables(Group and Movement tables) using node js (Express) and mongo DB. I already have a group Id coming from the Group table on my side, my question is, how can I save a movement( see point 3 ) with that group Id I have. I tried passing groupId: req.body.group._id and
groupId: req.body.group but I am never able to populate that variable
This are the two entities I've created:
1) GROUP ENTITY
const mongoose = require("mongoose")
const GroupSchema = mongoose.Schema({
name: {
type: String,
required: true
},
limit: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
movement: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Movement' }],
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
})
module.exports = mongoose.model("Group", GroupSchema)
2) MOVEMENT ENTITY
const mongoose = require("mongoose")
const MovementSchema = mongoose.Schema({
description: {
type: String,
required: true
},
value: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
group: { type: mongoose.Schema.Types.ObjectId, ref: 'Group' }
})
module.exports = mongoose.model("Movement", MovementSchema)
This is my movement router where I make the endpoints (Actual problem is here)
3) MovementRoute
const router = require('express').Router();
const verify = require('./verifyToken');
const User = require('../model/User');
const Group = require('../model/Group');
const Movement = require('../model/Movement');
// Create Movement
router.post('/', verify, async (req, res) => {
const post = new Movement({
description: req.body.description,
value: req.body.value,
groupId: req.body.group._id //**tried this**
});
try {
const savedMovement = await post.save()
res.status(200).send(res.json({ data: savedMovement }));
} catch (error) {
res.status(400).send(res.json({ message: error }));
}
});
module.exports = router;
Request sent
{
"description":"group1",
"value":"233",
"group":"5e506f3c56233d08f79bc8f3"
}
If console.log(req.body) gives you this:
{
description: 'group1',
value: '233',
group: '5e506f3c56233d08f79bc8f3'
}
..you should be able to do this:
router.post('/', verify, async (req, res) => {
console.log(req.body) // --> { description: 'group1', value: '233', group: '5e506f3c56233d08f79bc8f3' }
const post = new Movement({
description: req.body.description,
value: req.body.value,
groupId: req.body.group
// groupId: req.body.group._id //**tried this**
});
try {
const savedMovement = await post.save()
res.status(200).send(res.json({ data: savedMovement }));
} catch (error) {
res.status(400).send(res.json({ message: error }));
}
});

Resources