Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikermcneil/96ccd31757153dfe5e2d to your computer and use it in GitHub Desktop.
Save mikermcneil/96ccd31757153dfe5e2d to your computer and use it in GitHub Desktop.
Querying multiple models from a controller action in Sails
//...
showSchoolDetailPage: function (req, res) {
if (!req.param('id')) {
return res.badRequest('The id of the school (`id`) is a required parameter!');
}
// Look up the school, it's associated image, and the associated list of students.
School.findOne({
id: req.param('id')
})
.populate('image')
.populate('students')
.exec(function (err, school) {
if (err) {
return res.negotiate(err);
}
// Always be careful to do checks like these! In Node.js, if you throw an error
// in a callback, it will crash your server!
if (!school) {
return res.notFound();
}
// Let's say we also want to fetch the image for each student.
// Waterline doesn't support nested populate, but we can still just do things the
// ole fashioned way. We could either cache the image src URL as an attribute on the
// Student model, or do an additional "IN" query here. For the sake of demonstration,
// I'll do the latter:
File.find({
// This means we'll find files whose `photoOfStudent` attribute (a "model" association)
// is pointed at one of the students we just found associated with our school.
photoOfStudent: _.pluck(school.students, 'id')
}).exec(function (err, studentPhotos){
if (err) {
return res.negotiate(err);
}
// Now render the view, mashing together the different result sets into the locals
// we need for our view (if this was an API endpoint instead of a web page, we'd do
// the same thing, but call `res.json()`)
return res.view({
// It's a good idea to explicitly lay out the properties you're passing through to the response.
// Otherwise, it's just too easy to mess up and accidentally send down an encrypted password, etc.
// In other words, avoid doing `return res.view(school);`
name: school.name,
// If we didn't do this check, and the school _didn't_ have an image association, the server could crash.
imageSrc: school.image ? school.image.srcUrl : null,
allStudents: _.map(students, function (student){
// Figure out the source image URL for the student's photo.
var studentPhotoFileRecord = _.find(studentPhotos, {photoOfStudent: student.id});
var studentPhotoUrl;
if (studentPhotoFileRecord) { studentPhotoUrl = studentPhotoFileRecord.srcUrl; }
else { studentPhotoUrl = 'http://placeponi.es/150/150'; } // << default image src URL (sometimes it's better to take care of this kind of thing in the action where the student is updated or created-- but putting it here in this case for demonstration purposes)
return {
name: student.name,
slug: student.slug,
imageSrc: studentPhotoUrl,
studentDetailPageUrl: require('util').format('https://my-app.com/%s/%d', school.slug, student.slug)
};
})
});
});
});
}
// ...
@tranphuoctien
Copy link

Hi @mikermcneil do you know callback hell?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment