How to implementing beforeDestroy methods in SailsJS? - node.js

I'm new using sails JS.
I have methods like this
beforeDestroy: function(borrow, next){
return Book.find({id:borrow.product})
.then(function(){
Book.update(borrow.product, {'isBorrowed' : false})
})
.then(function(){
next();
})
.catch(function(error){
next(error);
});
}
When I tried to destroy data book 'IsBorrowed' still true, how to fix this when tried t delete data, firstly find id and secondly, change data book IsBorrowed to be false? Thank Advance

Here is a solution (to your original question - just switch the isBorrowed logic around as you now need it):
book.js
module.exports = {
schema: true,
attributes: {
name: {type: 'string', required: true},
desc: {type: 'text'},
isBorrowed: {type: 'boolean', defaultsTo: false}
}
};
bookBorrowed.js
module.exports = {
schema: true,
attributes: {
book: {model: 'Book'}
},
beforeDestroy: function (criteria, next) {
var bookId = criteria.where.id;
console.log(bookId);
Book.update({id: bookId}, {isBorrowed: true})
.exec(function (err, updatedBook) {
if (err) {
next('no book..');
}
console.log('updated book', updatedBook);
next();
});
}
};
Your problem was that you should consider the relationship with id, not object.
Also, the criteria parameter passed into beforeDestroy has a where object, it isn't the model. Also, the update() function takes an object criteria, see above.
If you wish to test, replace your bootstrap.js with the following snippet:
module.exports.bootstrap = function (cb) {
var bk = {name: 'name', desc: 'desc', isBorrowed: false};
Book.create(bk).exec(function (err, book) {
if (err) {
cb(err);
}
console.log('book: ', book);
var bb = {book: book.id};
BookBorrowed.create(bb).exec(function (err, bkBorrowed) {
if (err) {
cb(err);
}
console.log('bkBorrowed: ', bkBorrowed);
BookBorrowed.destroy({id: bkBorrowed.id}).exec(function (err, bkBorrowed) {
if (err) {
cb(err);
}
cb();
});
})
});
};

Related

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) {
..
}
);
}

MongooseJS findAndUpdate within Find loop

Been banging my head in the wall on this, so any help would be greatly appreciated. With MongooseJS, I'm doing a Model.find and then looping through those results and doing a findAndUpdate.
(basically, get list of URLS from MongooseJS, "ping" each URL to get a status, then update the DB with the status).
Schema
var serverSchema = new Schema({
github_id: { type: String, required: true },
url: { type: String, required: true },
check_interval: Number,
last_check: {
response_code: Number,
message: String,
time: Date
},
created_at: Date,
updated_at: Date
})
Here's a code snippet:
// Doesn't work
Server.find(function (err, items) {
if (err) return console.log(err)
items.forEach(function (item) {
var query = {url: item.url}
Server.findOneAndUpdate(query, {updated_at: Date.now()}, function (err, doc) {
if (err) return console.log(err)
console.log(doc)
})
})
})
// Works!
var query = {url: 'https://google.com'}
Server.findOneAndUpdate(query, {updated_at: Date.now()}, function (err, doc) {
if (err) return console.log(err)
console.log(doc)
})
With debugging on, I can see that the .find() is getting the data I want. However, it seems that he findOneAndUpdate within the .find() never runs (item.url is set correctly) and I don't get any errors, it just doesn't run.
Any help would be GREATLY appreciated.
You can achieve that without find and then update you can do this in only one update operation
Server.update({}, { $set: { updated_at: Date.now() } }, function(err, doc) {
if (err) return console.log(err) {
console.log(doc)
}
})
In case you need to loop on items for specific reason to handle urls then try the code below
var Server = require('../models/server');
Server.find(function(err, items) {
if (err) {
return console.log(err)
} else {
items.forEach(function(item) {
var query = { url: item.url }
Server.update(query, { $set: { updated_at: Date.now() } }, function(err, doc) {
if (err) return console.log(err)
console.log(doc)
})
})
}
})
Mongodb Connection:
var secrets = require('./secrets');
var mongoose = require('mongoose');
module.exports = function() {
var connect = function() {
var mongoLink = "";
if (process.env.NODE_ENV === 'production') {
mongoLink = secrets.db.prod;
} else {
mongoLink = secrets.db.dev;
}
mongoose.connect(mongoLink, function(err, res) {
if (err) {
console.log('Error connecting to: ' + mongoLink + '. ' + err);
} else {
console.log('Connected to: ' + mongoLink);
}
});
};
connect();
mongoose.connection.on('error', console.log);
mongoose.connection.on('disconnected', connect);
}

search queries in nodejs and mongodb and populated data

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

Mongoose reference overwritten

I am in a bit of a pickle. Whenever I create a new resume as a logged in user it doesn't add the resume id as an array. I.e, ["20293", "2932392", "32903239"]
Instead, it overwrites the current resume id in the users schema. Here is the code
UserSchema
const UserSchema = new Schema({
_vId: {
type: String,
default: id.generate()
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
accountType: {
type: String,
enum: ['Alphaneer', 'Administrator', 'Support', 'PRO'],
default: 'Alphaneer'
},
email: {
type: String,
required: true,
trim: true
},
username: {
type: String,
required: true,
trim: true,
unique: true
},
bio: {
type: String,
default: "No bio provided."
},
// TODO: Hash the password before inserting as a document :)
password: {
type: String,
required: true
},
createdAt: {
type: String,
default: moment(new Date()).format("MMM DD, YYYY") // "Sun, 3PM 17"
},
resume: [ { type: mongoose.Schema.ObjectId, ref: "Resume" } ]
});
Where I post my resume
// POST /dashboard/resume/create
router.post('/resume/create', (req, res, next) => {
Resume.create(req.body, (err, resume) => {
if (err) {
var err = new Error("Error:" + err);
err.status = 404;
next(err);
} else {
req.user = jwtDecode.decode(req.session.tokenID, 'secret');
//I am assuming that you have saved your resume and getting the saved object in `resume`, now update the logged in user in req.user
var user = req.user.sessionId;
var updateData = {
resume: resume._id
}
//save the updated user
User.findByIdAndUpdate(user, updateData, function(err, user) {
console.log(user);
if (err) {
res.json(err);
} else {
res.json(user);
}
})
}
})
});
gif of submitting new resumes
UPDATE:
error picture
UPDATED CODE:
// POST /dashboard/resume/create
router.post('/resume/create', (req, res, next) => {
Resume.create(req.body, (err, resume) => {
if (err) {
var err = new Error("Error:" + err);
err.status = 404;
next(err);
} else {
req.user = jwtDecode.decode(req.session.tokenID, 'secret');
//I am assuming that you have saved your resume and getting the saved object in `resume`, now update the logged in user in req.user
var user = req.user.sessionId;
var updateData = {
resume: resume._id
}
//save the updated user
User.findById(user, function(err, user) {
console.log(user);
if (err) {
res.json(err);
} else {
user.resume.push(resume.id)
user.save(function(user) {
return res.json(user);
});
}
})
}
})
});
This is wrong:
var user = req.user.sessionId;
var updateData = {
resume: resume._id
}
//save the updated user
User.findByIdAndUpdate(user, updateData, function(err, user) {
console.log(user);
if (err) {
res.json(err);
} else {
res.json(user);
}
});
The resume field is an array and you are manipulating it as a string field. The method findOneAndUpdate do two things:
Find the document by it's id
Update it with the new data
The second argument is the new data to set. So, the second step is translated to:
User.upate({ _id: user }, { resume: resume._id });
Can you see what's wrong? resume must store an array of resume's id and your are setting a id as value. Obviously this will throw an MongooseError.
Your second shot is correct but has a typo error:
User.findById(user, function(err, user) {
console.log(user);
if (err) {
res.json(err);
} else {
user.resume.push(resume.id)
user.save(function(user) {
return res.json(user);
});
}
});
You must add the _id field since this is the ObjectID of the new created document (resume). So, you need to do user.resume.push(resume._id) instead.
Update
According with your last comment, you want to populate your User model, that is, through association id's retrieve all model data. In this case, is recommended that the resumes array change like this:
...
resumes: [
{
resume: {
type: Schema.Types.ObjectId,
ref: 'Resume'
}
}
]
To populate the User document with all Resume data you just need to reference the resume key in resumes field array.
User.findById(user, function(err, user) {
if (err) {
return res.json({ success: false, message: err.message });
}
user.resume.push(resume.id)
user.save(function(err, user) {
if (err) {
return res.json({ success: false, message: err.message });
}
// save was fine, finally return the user document populated
User.findById(user).populate('resumes.resume').exec(function(err, u) {
return res.json(u);
});
});
}
});
The populate method accepts a string with the fields that we want fill with it model data. In your case is an only field (resume). After run the query, you will get something like this:
{
_id: a939v0240mf0205jf48ut84sdfdjg4,
...,
resumes: [
resume: {
_id: f940tndfq4ut84jofgh03ut85dg9454g,
title: 'Some title'
},
...
]
}
Just to follow up on my comment regarding how I suggest you solve the issue:
router.post('/resume/create', (req, res, next) => {
Resume.create(req.body, (err, resume) => {
if (err) {
var err = new Error("Error:" + err);
err.status = 404;
next(err);
} else {
req.user = jwtDecode.decode(req.session.tokenID, 'secret');
//Here, instead of creating a new key entry for resume, you rather push new resume-id into the resume property of the "found user".
//find, update and save the user
User.findOne({_id: req.user.sessionId}, function (err, userToUpdate) {
userToUpdate.toJSON().resume.push(resume.id);
userToUpdate.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
});
}
})
});
I left the rest of your code (saving new resume) untouched - I assume that part works. Give this a try and let me know if you encounter some problems.

Mongoose method to return id

I'm struggling to code a method in my mongoose model that returns only an id of a specific record.
This is my (simplified) schema:
var PersonaSchema = new Schema({
email: { type: String, unique: true },
personal_firstname: String,
created_at: { type: Date },
updated_at: { type: Date }
});
I would like to search for a record by email, than return the id if it exists. Currently I have this method setup as a static method, which does not work as suspected. It does not return the id, but the whole mongoose object.
PersonaSchema.statics = {
getPersonaId: function getPersonaId(email, cb) {
this.findOne({ email: email }).select("_id").exec(function(err, persona) {
if(err) {
throw err;
} else {
if(persona){
return persona._id;
} else {
return;
}
}
});
}
}
Any pointers are much appreciated.
EDIT: I was not quite clear in my question. What I want to do is get the persona id as a single value in my controller method.
Underneath I have a now working version, with a callback version. However, I would like it to be without a callback. So that I send an email to a static function, which returns the persona._id. How would I do that, without a callback?
var personaId = Persona.addPersonaId(personaData, function(err, persona, data) {
if(err){
console.log(err)
} else {
console.log(data);
}
});
You could have this in the model:
PersonaSchema.statics = {
getPersonaId: function (email, cb) {
this.findOne({ email: email }).select('_id').exec(cb);
}
};
And this somewhere else:
PersonaSchema.model.getPersonaId('test#test.com', function (err, persona) {
if (err) {
// handle error, express example:
return next(err);
}
// here you have
console.log(persona._id);
});
use callback instead of return.
.exec(function(err, persona) {
if(err) {
return cb( err, persona );
}
cb( null, {id: persona._id} );
});

Resources