search queries in nodejs and mongodb and populated data - node.js

i have a web app that's written in nodejs and mongodb, i have the following two models
var TeacherSchema = new Schema({
school_id:[{type: Schema.Types.ObjectId, ref: 'School'}],
name: String,
subjects: [{type: Schema.Types.ObjectId, ref: 'Subject'}],
});
var SubjectSchema = new Schema({
title : String,
school_id:[{type: Schema.Types.ObjectId, ref: 'School'}]
});
i wrote an api that searches throw the teacher or subjects
router.get("/field-teacher-subject", function (req, res) {
var school_id= req.query.schoolId;
Subject.find(school_id:'school_id,function (err, subjects) {
if (err) {
console.log(err);
res.json({status: "error", message: err.message});
} else {
var sub_array=[];
for(var q in subjects){
sub_array.push(subjects[q]._id);
}
Teacher.find({subjects:{$in :sub_array }},{first_name:true, father_name:true, last_name : true, subjects:true}).populate('subjects')
.exec(function(tech) {
console.log("hello: ");
var subjeto = [];
if(tech){
for(var p in tech){
subjeto.push(tech[p].subjects);
}
}
res.json({status: "success", message: "subjects returned",
items: tech});
}).catch(function(err){
if(err){
res.json({status:"error",
message:"error occurred"+err.message});
return;
}
});
}
}).limit(parseInt(req.query.max));
});
THIS RETURNS null when i search for a name,
what is the best way to solve this

Hard to know what you are asking but your code has few errors. Let's clean up your code, shall we?
router.get("/field-teacher-subject", function (req, res) {
// get subjects
Subject
.find({ school_id: req.query.schoolId }) // 1st argument is an object
.limit(parseInt(req.query.max)) // should go before
.exec(function (err, subjects) { // use .exec()
if (err) {
console.log(err);
return res.json({ status: "error", message: err.message });
}
// get subject IDs
var sub_array = subjects.map(function (subject) { return subject._id; });
// get teachers assigned to subjects
Teacher
.find({ subjects: { $in: sub_array }})
.select('first_name father_name last_name subjects')
.populate('subjects')
.exec(function(err, teachers) { // 1st argument is an error
if (err) {
console.log(err);
return res.json({status: "error", message: err.message });
}
var subjeto = teachers.map(function (teacher) { return teacher.subjects; });
res.json({status: "success", message: "subjects returned", items: teachers });
});
});
});
Useful links:
See 3rd example in doc on how to use .limit() and .exec().
.map()
You tried to use .exec() like .then() and .catch() in your second query

Related

How to update object in array of object of a document in mongoose?

My User Schema is like this
{
_id:ObjectId("6e9465528a15ba6")
name: 'XYZ',
email: 'abc#gmail.com',
transactions: [
{
_id:ObjectId("5e946557a5128a15ba6"),
date: 2020-04-09T06:00:30.000Z,
type: 'type1',
category: 'category1',
description: 'some desc',
}
]
}
I want to update some fields of transaction with specific id. But not happening.
I tried the solution answered to
Mongoose, update values in array of objects this question.
May be my _id is of type ObjectId and id coming from my request is String?
So how can I solve this problem?
My code is like this but still getiing error user.transactions._id is not function
app.post('/api/update', function (req, res) {
const {
id,
email,
date,
type,
category,
description
} = req.body;
User.findOne({email}, function (err, user) {
if (err) {
console.error(err);
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!user) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
const objectId = mongoose.Types.ObjectId(id);
let transaction = user.transactions._id(objectId);
transaction.date = date;
transaction.type = type;
transaction.category = category;
transaction.description = description;
user.save((err, data) => {
if (err) return res.send(err);
return res.sendStatus(200);
});
}
});
});
fortunately I had to do something similar recently, so I suggest you to have a look at this page from Mongoose docs in the case I miss something, but basically you have to find the document first and then update its array of objects.
I'd try something like this:
User.findOne({ _id: your_user_id }, (err, data) => {
if (err) return console.log(err);
if (data) {
//Mongoose has a special method (id) for subdocuments
var transaction = data.transactions.id(your_transaction_id);
date: new Date(),
type: 'type2',
category: 'category2',
description: 'whatever',
//data.save() saves everything, document and subdocument
data.save((err, data) => {
if (err) return console.log(err);
done(null, data);
});
}

How to use findByIdAndUpdate on mongodb?

I am a noobie in coding and I am having an issue with how to use properly MongoDB. I have a parent object classroom containing an array of objects - comments. I am trying to update the content of 1 selected comment.
originally I updated the state of the whole "classroom" in the react and passed all the data and $set {req.body} in findByIdAndUpdate.
I want to achieve the same result if I only pass to my axios request classId, commentId and comment data and not whole classroom / all comments
I tried to filter selected comment out of the array of comments and concat updated comment, but that did not work. Clearly, I have any idea what is going on and docs don't make it any easier for me to understand.
my classroom schema:
var ClassroomSchema = new Schema({
title: String,
teacher: String,
info: String,
image_url: String,
comments: [Comment.schema]
});
comment schema:
var CommentSchema = new Schema()
CommentSchema.add({
content: String,
comments: [CommentSchema],
created_at: {
type: Date,
default: Date.now
}
});
original solution:
function update(req, res){
Comment.findById(req.params.comment_id, function(err, comment) {
if(err) res.send(err)
comment.content = req.body.content;
comment.save();
console.log(req.body.comments)
Classroom.findByIdAndUpdate(req.params.classroom_id,
{$set: req.body}, function(err, classroom){
if (err) {
console.log(err);
res.send(err);
} else {
commentToUpdate = req.body.commentData;
res.json(classroom);
}
});
});
}
my current failing atempt:
function update(req, res){
console.log('update => req.body: ', req.body);
console.log('req.params', req.params)
Comment.findById(req.params.comment_id, function(err, comment) {
if(err) res.send(err)
comment.content = req.body.content;
comment.save();
console.log('comment: ', comment);
Classroom.findById(req.params.classroom_id, function(err, classroom) {
console.log('CLASSROOM findByIdAndUpdate classroom: ', classroom)
// console.log('reg.body: ', req.body)
if (err) {
console.warn('Error updating comment', err);
res.send(err);
} else {
// commentToUpdate = req.body.commentData;
old_comments = classroom.comments;
console.log('comments: ', old_comments);
Classroom.findByIdAndUpdate(req.params.classroom_id,
{$set:
{ comments: old_comments.filter(comt._id !== comment._id).concat(comment)}
}, function(err, updatedClassroom) {
if (err) {
console.warn(err);
} else {
res.json(updatedClassroom);
}
});
}
});
});
}
haven't tested, but try this.
function update(req, res) {
Classroom.update(
{ _id: req.params.classroom_id, "comments._id": req.params.comment_id },
{ $set: { "comments.$.content": req.body.content } },
function(err) {
..
}
);
}

Join two collections using mongoose and get data from both

I have two collections User and Taxdetails, I want the name and phone number from User and payment details from Taxdetails joingin on user_id in both collections.
I am doing this:
User
.find()
.exec(function(err, userDetails) {
if (err) {
console.log("error in user collection");
res
.status(400)
.json({ 'message':'error','success':false });
} else {
var userid = userDetails.map(function(obj) {
return obj._id;
});
Taxdetail
.find()
.exec({ user_id : { $in : userid } },function(err, requests) {
if(err){
console.log("error in TaxDetails collection");
res
.status(400)
.json({ 'message':'error','success':false });
}else{
console.log("Success, got some data");
res
.status(200)
.json(requests);
}
});
}
});
You may want use referenced schema in your User schema and then populate it like this:
var taxDetailSchema = new Schema({
title: String
});
var taxDetail = mongoose.model('taxDetail', taxDetailSchema);
var userSchema = new Schema({
name: String,
taxDetails: [{ type: Schema.Types.ObjectId, ref: 'taxDetail' }]
});
Your query would look like this:
User
.find()
.populate('taxDetails')
.exec(function(err, users) {
});
The users should look like this:
[
{
name: 'Some Name',
taxDetails: [
{ title: 'Some Title' },
{ title: 'Some other Title' }
]
}
]
Mongoose documentation here
Hope it helps

MongoDB: Updating arrays of sub documents after document deletion

I have an API in which I am deleting 'course' documents in the following way:
module.exports.deleteCourse = function(req, res){
var courseid = req.params.courseid;
if(courseid){
Course.findByIdAndRemove(courseid, function(err, course){
if(err){
sendJSONResponse(res, 404, err);
return;
}
sendJSONResponse(res, 204, null)
});
} else{
sendJSONResponse(res, 404, {"message":"NoId"});
}
};
This is successful in deleting the course from the database, as is shown when attempting to find it by id.
The issue is that in user documents:
var instructorSchema = new mongoose.Schema({
name: {type: String,
unique: true,
required: true},
password: {type: String,
required: true},
courses: [course.schema]
});
If the document was pushed to the courses array it remains after the deletion method.
So my question. Is there a relatively painless way to keep this document updated after deletes?
Thanks.
Add a class method for course using statics, where you delete both the course and its dependencies.
Assuming you are storing ids in courses array:
var Instructor = require('./instructor');
courseSchema.statics = {
removeOneWithDependencies : function(id, done){
this.findByIdAndRemove(id, function(err, course){
if(err){
return done(err);
}
else{
//Removes the course id from courses array of all instructor docs
Instructor.update({courses: course._id}, { $pullAll: {courses: [course._id] } }, {multi: true}, function(err){ //http://stackoverflow.com/a/27917378/
if(err){
return done(err);
}
else{
return done();
}
})
}
});
}
}
In case you are storing course documents in courses array you need to change the update query to:
Instructor.update({"courses._id": course._id}, { $pull: {courses:{_id: course._id} } }, {multi: true}, function(err){ //http://stackoverflow.com/a/15122017/
Finally use the above method in your API:
module.exports.deleteCourse = function(req, res){
var courseid = req.params.courseid;
if(courseid){
Course.removeOneWithDependencies(courseid, function(err){
if(err){
return sendJSONResponse(res, 500, err);
}
else{
return sendJSONResponse(res, 204, null);
}
});
} else{
sendJSONResponse(res, 404, {"message":"NoId"});
}
};

mongoose save if new refs

If you want to know what's the problem in this thread in two words: I'm trying to accomplish a mongoose function findOrAdd(): if the Id I'm searching for isn't present, I should add a new document. After that (that's why I need some sync functions) I need to do another query based on the new ObjectIds.
This is my Post Schema
var com_post_schema = new Schema({
content: { type: String, required: true },
postedBy: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'com_user'
}]
});
and my User Schema
var com_user_schema = new Schema({
name: { type: String, required: true },
age: {type:Number}
});
So a post can have more than one author.
My problem: an author can be an existent user (chosen in bootstrap-tokenfield) or a new user, see this json example:
{
"content":"post content",
"postedBy":[
{
"_id":"56a60a972b70225014753d1a",
"name":"Paul",
"age":20,
"__v":0,
"value":"Paul",
"label":"Paul"
},
{
"value":"John",
"label":"John"
}
]
}
The user Paul is already present in 'com_user' collection, I have to save the user John in 'com_user' and then save the post with both user ObjectIds refs (the fields 'value' and 'label' are sent by bootstrap-tokenfield).
I'm not clear how can I do that.
EDIT this is my current code I still have sync problems. I made some tests and I see randomly in console "New post added" and then "User not found.."
Try with 3 users and see..
app.post('/api/community/posts', function(req,res){
var arr=[],i=0;
req.body.postedBy.forEach(function(el){
com_user.findById(el._id, function (err, user) {
if(user) {
console.log("User found!");
console.log(user);
arr.push(mongoose.Types.ObjectId(user._id ));
i++;
if(i==req.body.postedBy.length-1) {
console.log('UFi'+i)
console.log(arr)
var com_post1= new com_post({
content:req.body.content,
postedBy:arr,
});
com_post1.save(function(err){
if(!err){
console.log("New post added!");
res.json({"New post added! ":req.body.content});
}
else {
res.json({"Error adding post":'error'});
error(err)
}
});
}
}
else {
var com_user1= new com_user({
name:el.label,
age: 20
});
com_user1.save(function(err,newuser){
if(err)
console.log(err)
else {
console.log('User not found and just added!');
console.log(newuser)
arr.push(mongoose.Types.ObjectId(newuser._id));
console.log(arr)
i++;
if(i==req.body.postedBy.length-1) {
console.log('NUFi'+i)
console.log(arr)
var com_post1= new com_post({
content:req.body.content,
postedBy:arr,
});
com_post1.save(function(err){
if(!err){
console.log("New post added!");
res.json({"New post added! ":req.body.content});
}
else {
res.json({"Error adding post":'error'});
error(err)
}
});
}
}
});
}
});
});
});
its because the code after forEach gets executed before the forEach is completed. Try it like this
app.post('/api/community/posts', function(req,res){
var arr=[],i=0;
req.body.postedBy.forEach(function(el){
com_user.findById(el._id, function (err, user) {
if(user) {
console.log("User found!");
console.log(user);
arr.push(mongoose.Types.ObjectId(user._id ));
i++;
if(i==req.body.postedBy.length-1) { //to ensure forEach is complete
console.log(arr)
var com_post1= new com_post({
content:req.body.content,
postedBy:arr,
});
com_post1.save(function(err){
if(!err)
res.json({"New post added! ":req.body.content});
else {
res.json({"Error adding post":'error'});
error(err)
}
});
}
}
else {
var com_user1= new com_user({
name:el.label,
age: 20
});
com_user1.save(function(err,newuser){
if(err)
console.log(err)
else {
console.log('User not found and just added!');
console.log(newuser)
arr.push(mongoose.Types.ObjectId(newuser._id));
i++;
if(i==req.body.postedBy.length-1) {
console.log(arr)
var com_post1= new com_post({
content:req.body.content,
postedBy:arr,
});
com_post1.save(function(err){
if(!err)
res.json({"New post added! ":req.body.content});
else {
res.json({"Error adding post":'error'});
error(err)
}
});
}
}
});
}
});
});

Resources