I'm running a find inside the following toJSON in the model but it return returns the object before the find completes. How can I wait until the find completes before firing the return?
toJSON: function() {
var obj = this.toObject();
Comment.find({
postID: obj.id
}).limit(2).sort('createdAt DESC').exec(function(err, comments) {
obj.comments = comments; //this is not reflected in return obj
if (obj.isTrue) {
//yes
} else {
//no
}
});
return obj; // obj.comments not reflected :(
}
The goal is for obj.comments to be in obj when it is returned.
That's because .exec takes a callback function (in your case function(err, comments){...}) which is asynchronously executed (i.e. it's executed somewhen later, in your case after return obj). This is a common problem for people new to JavaScript. You have two options:
Make your toJSON function also take a callback (a callback function is a function that is passed to another function as an argument. That function in turn is then called a higher-order function):
var toJSON = function(callback) {
var obj = this.toObject();
Comment.find({
postID: obj.id
}).limit(2).sort('createdAt DESC').exec(function(err, comments) {
obj.comments = comments;
if (obj.isTrue) {
//yes
} else {
//no
}
callback(obj);
});
}
usage:
toJSON( function(obj) {
//now obj is updated
});
Use a promise library like Q and have toJSON return a promise:
var toJSON = function() {
var deferred = Q.defer();
var obj = this.toObject();
Comment.find({
postID: obj.id
}).limit(2).sort('createdAt DESC').exec(function(err, comments) {
obj.comments = comments;
if (obj.isTrue) {
//yes
} else {
//no
}
deferred.resolve(obj);
});
return deferred.promise;
}
usage:
toJSON().then( function(obj) {
//now obj is updated
});
The solution ended up being to add an associate between posts and comments.
You can find documentation on that here: http://sailsjs.org/#/documentation/concepts/ORM/Associations
For example, in the post model add an attribute like so
comments: {
collection: 'comment',
via: 'postID'
},
And in the comments model add this attribute
postId: {
model: 'hacks',
type: 'STRING',
required: true
},
when adding new documents set a comment's postId to the id of the post you'd like to associate. Then in the post controller when you are finding posts add populate like so
.populate('comments', {
limit: 3,
sort: 'createdAt DESC'
}).exec(...