Have looked through the bluebird readMe examples, and am still wondering how to implement/convert some async code to involve promises with .then..
There are a number of ifStatements in here, though the main point is that while looping through the toArray
, if the element
exists in the database (findOne) then assign it to a variable to .push it to a field in an embedded doc of the new (.post & .save) db doc.
Here's the current async code that consequently runs the findOne after .save .. but it needs to run before:
// create a story (accessed at POST http://localhost:4200/api/v1/story)
.post(function(req, res) {
console.log('posting a new Story..from: ' + res.locals._id + '..' + res.locals.username );
var story = new Models.Story();
var toArray = req.body.to;
console.log(toArray); // [ 'user1', 'user2', 'user3' ]
toArray.forEach(toArrayLoop);
function toArrayLoop(element, index, array){
console.log('element: ' + element); // 'user1' .. 'user2' .. 'user3'
var out = false; // if sent to Self, out = true
if (element == res.locals.username) {out = true; console.log('to element: ' + element + ' == res.locals.username: ' + res.locals.username)}
var toUserId = '';
if (element) {
Models.User.findOne({username: element}, function (err, user) {
if (user) {
if (err) {
console.log(err);
res.send(err);
}
console.log('user._id = ' + user._id);
toUserId = user._id;
} else {
toUserId = '';
console.log('toUserId = ' + toUserId);
}
});
}
story.to.push({
user : toUserId, // push the findOne user._id
username : element, // push the toArray element
view :
{
inbox: true,
outbox: out,
archive: false,
},
updated : req.body.nowDatetime
});
}
var archive = false;
console.log('req.body.archive = ' + req.body.archive);
if (req.body.archive == 'true') { archive = true; console.log('archive = ' + archive); };
var in = false;
toArray.forEach(fromSelfLoop);
function fromSelfLoop(element, index, array){
console.log('checking if sent to Self: ' + element); // 'user1' .. if matches res.locals: (sent from/to Self)
if (element == res.locals.username) {in = true; console.log('from element: ' + element + ' == res.locals.username: ' + res.locals.username)}
} // if sent to Self, archive = true
story.from.push({
user : res.locals._id,
username : res.locals.username,
view :
{
inbox: in,
outbox: true,
archive: archive,
},
updated : req.body.nowDatetime
});
story.title = req.body.title;
// ..even more doc val assignments..
console.log('To: ' + req.body.to);
console.log('Story: ' + req.body.title);
story.save(function(err, result) {
if (err) {
console.log(err);
res.send(err);
}
console.log("The result: ", result);
res.json({ message: 'Story "' + story.title + '" Created' });
});
console.log('post success!');
})
You're way overkilling it in my opinion, Promises provide ways to synchronize this out of the box seamlessly.
You can use promise aggregation methods (in this case .join
and .props
) to map directly to the properties and get the values.
Assuming you promisified Mongoose (so Bluebird promises rather than Mongoose ones).
var story = new Models.Story();
var toArray = req.body.to; // [ 'user1', 'user2', 'user3' ]
var to = Promise.map(toArray,function(element){
return Promise.props({ // resolves all properties
user : Models.User.findOneAsync({username: element}),
username : element, // push the toArray element
view : {
inbox: true,
outbox: element == res.locals.user.username,
archive: false
},
updated : req.body.nowDatetime
});
});
var from = Promise.map(toArray,function(element){ // can be a normal map
return Promise.props({
user : res.locals._id,
username : res.locals.username,
view : {
inbox: element == res.locals.user.username,
outbox: true,
archive: archive,
},
updated : req.body.nowDatetime
});
});
Promise.join(to, from, function(to, from){
story.to = to;
story.from = from;
story.title = req.body.title;
return story.save();
}).then(function(){
console.log("Success! Story saved!");
}).catch(Promise.OperationalError, function(e){
// handle error in Mongoose save findOne etc, res.send(...)
}).catch(function(e){
// handle other exceptions here, this is most likely
// a 500 error where the top one is a 4XX, but pay close
// attention to how you handle errors here
});