I have the following code and I would like to avoid nested callbacks:
app.get '/performers', (req, res) ->
conductor = require('models/conductor').init().model
soloist = require('models/soloist').init().model
orchestra = require('models/orchestra').init().model
chamber = require('models/chamber').init().model
performers = {}
conductor.find {}, (err, result) ->
performers.conductor = result
soloist.find {}, (err, result) ->
performers.soloist = result
orchestra.find {}, (err, result) ->
performers.orchestra = result
chamber.find {}, (err, result) ->
performers.chamber = result
res.json performers
Any ideas?
I find the async library to be a cleaner solution than promises for this sort of thing. For this specific case, async.parallel would work well.
I'm not overly familiar with coffeescript, but it would look something like this:
performers = {}
async.parallel [
(callback) ->
conductor.find {}, (err, result) ->
performers.conductor = result
callback err
(callback) ->
soloist.find {}, (err, result) ->
performers.soloist = result
callback err
(callback) ->
orchestra.find {}, (err, result) ->
performers.orchestra = result
callback err
(callback) ->
chamber.find {}, (err, result) ->
performers.chamber = result
callback err
], (err) ->
res.json performers
You can also organize your code like this:
exports.index = function(req, res){
var _self = {};
var foundItems = function(err, items){
_self.items = items;
res.render('index', { user: _self.user, items: _self.items, lists: _self.lists });
};
var foundLists = function(err, lists){
_self.lists = lists;
Items.find().exec(foundItems);
};
var foundUser = function(err, user){
_self.user = user;
List.find().exec(foundLists);
};
User.findById(user).exec(foundUser);
};
Related
I am trying to use async.waterfall in the exports handler, and call functions sequentially. One of the function is related to MQTT message publishing. While the functions are being called, but when the MQTT function gets called, it just stops and not calls the require ('MQTT').
exports.handler = function(event, context) {
var async = require('async');
async.waterfall([
function(callback) {
retrieveEmailId(apiAccessToken,callback)
},
function(emailId, callback) {
retrieveDeviceDetails(callback)
},
function(deviceDetail, callback) {
publishMsg(callback)
}
], function(err, result) {
if (err) console.log('Error :: \n' + err);
});
}
function retrieveEmailId(accessToken, callback) {
var getEmailFromAlexaProfileObj = require('./GetEmailFromAlexaProfile');
getEmailFromAlexaProfileObj.doIt(accessToken, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function retrieveDeviceDetails(callback) {
var getDevcieDetailsObj = require('./GetDevcieDetails');
getDeviceDetailsObj.doIt(null, function(returnVal) {
console.log(returnVal);
callback(null, returnVal)
});
}
function publishMsg() {
var mqtt = require('mqtt');
var options = {
clientId: "xxx",
username: "yyy",
password: "zzz",
clean: true
};
var client = mqtt.connect("mqtt://xxx.com", options)
client.on("connect", function () {
client.publish('xxx/yyy/L1', "1", options);
client.end();
});
}
Have you tried running the code locally using "lambda-local"? Does that sequence of call work along with the last one that is MQTT? What have you noticed when you invoke "require('mqtt')" within lambda?
Problem got resolved if the require variable is done prior to exports.handler.
for example....
var AWS = require('aws-sdk');
var async = require('async');
exports.handler = function(event, context) {
....
}
Am trying to get the items from DynamoDB table based on the current date. Using the date value in string format when am trying to run the below piece of code, its error out saying:
{
"errorMessage": "ERROR: Dynamo failed: TypeError: Cannot read property 'datatype' of undefined"
}
Below is the piece of code:
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
console.log("Context received:\n", JSON.stringify(context));
var doc = require('dynamodb-doc');
var dynamodb = new doc.DynamoDB();
var params = {
Key: {
"abc" : datetime1
},
TableName: 'myTable',
ProjectionExpression: 'message'
};
var Message = callback();
var datetiem = new Date().toISOString().split('T')[0];
console.log('date is ', datetiem); // prints 2018-01-09
var datetime1 = JSON.stringify(datetiem);
console.log(datetime1); //prints "2018-01-09"
function callback (message) {
dynamodb.getItem(params, function (err, data) {
if (err) {
context.fail('ERROR: Dynamo failed: ' + err);
} else {
console.log('Dynamo Success: ' + JSON.stringify(data, null, ' '));
console.log('data', data)
let Message = data['Item'].message;
console.log('test',Message);
}
});
}
};
It runs fine if I pass the value directly i.e. "abc" : "2018-01-09"
Can someone please advice?
I'm not sure your datetime1 variable is defined when you use it in parameters. Try this:
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
console.log("Context received:\n", JSON.stringify(context));
var doc = require('dynamodb-doc');
var dynamodb = new doc.DynamoDB();
var Message = callback();
var datetiem = new Date().toISOString().split('T')[0];
console.log('date is ', datetiem); // prints 2018-01-09
var datetime1 = JSON.stringify(datetiem);
console.log(datetime1); //prints "2018-01-09"
var params = {
Key: {
"abc" : datetime1
},
TableName: 'myTable',
ProjectionExpression: 'message'
};
function callback (message) {
dynamodb.getItem(params, function (err, data) {
if (err) {
context.fail('ERROR: Dynamo failed: ' + err);
} else {
console.log('Dynamo Success: ' + JSON.stringify(data, null, ' '));
console.log('data', data)
let Message = data['Item'].message;
console.log('test',Message);
}
});
}
};
I'm writing a lambda function to get the resources by posting the phone number. below is my code.
exports.handle = function (e, ctx, cb) {
var body = JSON.parse(e.body);
var params = {
TableName: 'userAddresses',
FilterExpression: '#phone = :phone',
ExpressionAttributeNames: {
"#phone": "phone"
},
ExpressionAttributeValues: {
":phone": body.phone
}
}
dynamodb.scan(params).promise().then(function (data) {
var uw = data.Items[0];
var res = {
"statusCode": 200,
"headers": {},
"body": JSON.stringify(uw)
};
ctx.succeed(res);
});
}
this is working fine. but I want to do the same with put and patch. Can some one please point me in a right direction.
for patch, it should be something like, the phone should be passed as a queryParameter and the body to be updated in just json body
Thanks
Is the phone number a hash key? If so, use dynamodb.get() or dynamodb.query() instead...
Here's a quick and dirty example, it may help you to get started with DynamoDB updates:
const AWS = require('aws-sdk);
const bluebird = require('bluebird');
AWS.config.setPromisesDependency(bluebird);
const dynamodb = new AWS.DynamoDB.DocumentClient();
let update = (id, attributes) => {
var params = {
TableName: 'MyTableName',
Key: {
myHashKeyAttr: id
},
AttributeUpdates: attributes
};
return dynamodb.update(params).promise();
};
exports.handler = (event, context, callback) => {
console.log(JSON.stringify(event, null, 2));
let body = JSON.parse(event.body);
let attributes = {
firstName: {
Action: 'PUT',
Value: body.firstName
},
lastName: {
Action: 'PUT',
Value: body.lastName
},
updatedAt: {
Action: 'PUT',
Value: new Date()
}
};
// only if the phone number is a hash key...
update(event.queryStringParameters.phone, attributes)
.then(
(result) => {
console.log(result);
callback({
statusCode: 200,
headers: {},
body: JSON.stringify({message: 'updated!'})
});
}
).catch(
(error) => {
console.error(error);
callback({
statusCode: 500,
headers: {},
body: JSON.stringify({message: 'ops!'})
});
}
);
}
I'm trying to save image id after insert in FS.Collection.
Insert array
var item = {
name: $(value).find('#name').val(),
article: $(value).find('#article').val(),
description: $(value).find('#description').val(),
price: $(value).find('#price').val(),
sizes: $(value).find('#sizes').val()
};
file = $(value).find('#attachmentName')[0].files[0];
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item = _.extend(item, {
image: fileObj._id.toString()
});
});
}
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
collectionInsert method
Meteor.methods({
collectionInsert: function(postAttributes) {
check(Meteor.userId(), String);
check(postAttributes, {
name: String,
article: String,
description: String,
price: String,
sizes: String,
image: String
});
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.profile.name,
timestamp: new Date(),
views: 0
});
var collectionId = Collections.insert(post);
return {
_id: collectionId
};
}
});
Then i'm got Exception
Exception while invoking method 'collectionInsert' Error: Match error: Missing key 'image'
In console log i have item value
...
image: "4J55dyGb5DpqbCXGG"
...
I'm trying to change check property to image: Match.Optional([String]) and image: Match.Any - no effect
I think the issue here is that your insert method is non-blocking, which means that you probably haven't received the fileObj nor extended item before passing it to the method call. Maybe you should try to make the method call in the insert callback, like this:
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item.image = fileObj._id.toString(); // don't need _.extend
// item should now be extended
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
});
}
By the way, you should probably store the result of $(value) instead of constructing the same jQuery object over and over. Just a minor optimization, but improves readability nonetheless.
var $value = $(value);
var item = {
name: $value.find('#name').val(),
...
};
I'm using caolan/async specifically .parallel() and I'm assembling an object of strings. When there's an error the whole thing exists and doesn't finish, even the processes without errors.
async.parallel({
"color": color,
"brand": brand,
"sku": sku,
}, function(err, result) {
console.log(err);
console.log(result);
});
If brand returns an error, I don't get any information. I'd rather brand:false. How can I achieve this?
async.parallelPlus = function(functions, callback) {
var wrap = function(func) {
return function(callback) {
func(function(err, value) {
if (err) return callback(null, false);
return callback(null, value);
});
}
}
var newFunctions = {};
for (var func in functions) {
newFunctions[func] = wrap(functions[func]);
}
return async.parallel(newFunctions, callback);
}