Created
September 16, 2015 19:05
-
-
Save mikermcneil/96ccd31757153dfe5e2d to your computer and use it in GitHub Desktop.
Querying multiple models from a controller action in Sails
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//... | |
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) | |
}; | |
}) | |
}); | |
}); | |
}); | |
} | |
// ... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @mikermcneil do you know callback hell?