error: TypeError: handlerInput.serviceClientFactory.getReminderManagementServiceClient is not a function - alexa-skills-kit

I am trying to create a Reminder in Alexa to alert me in x amount of minutes but keep getting getReminderManagementServiceClient is not a function, even though i checked the Index file and updated the SDK.
const client = handlerInput.serviceClientFactory.getReminderManagementServiceClient();
var date = new Date();
var timestamp = date.getTime();
const reminderRequest = {
"trigger": {
"type" : "SCHEDULED_RELATIVE",
"offsetInSeconds" : "30"
},
"alertInfo": {
"spokenInfo": {
"content": [{
"locale": event.request.locale,
//"locale": "en-US",
"text": `The price of ${companyName} now is ${latestPrice}`
}]
}
},
"pushNotification" : {
"status" : "ENABLED"
}
}
const reminderResponse = await client.createReminder(reminderRequest);
console.log(JSON.stringify(reminderResponse));
error: TypeError: handlerInput.serviceClientFactory.getReminderManagementServiceClient is not a function

Your answer helped me. I needed to update the sdk. Here are a few things that I also had to do to get it working. Maybe this can help you
Are you using ask-sdk-core?
const Alexa = require('ask-sdk-core');
Do you have the .withApiClient(new Alexa.DefaultApiClient())? https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs/issues/356
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(...)
.withApiClient(new Alexa.DefaultApiClient())
.withSkillId(...)
.lambda();
Good luck!

Related

How to dynamically update an attribute in a dynamodb item?

I created an item in dynamodb using Node js, the item has multiple attributes such as brand, category, discount, validity, etc. I am using uuid to generate ids for each item. Now let's say I want to update the validity attribute of the item, in which case I am currently sending the entire json object with the value of validity modified to the new value.
This is definitely not optimal, please help me find an optimal solution.
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: {
'#discount': 'discount',
},
ExpressionAttributeValues: {
':brand': data.brand,
':category': data.category,
':discount': data.discount,
':denominations': data.denominations,
":validity": data.validity,
":redemption": data.redemption
},
UpdateExpression: 'SET #discount = :discount, denominations = :denominations, brand = :brand, category = :category, validity = :validity, redemption = :redemption',
ReturnValues: 'ALL_NEW',
};
I want to send just the attribute I want to update with the new value, if I want to change the validity from 6 months to 8 months, I should just send something like:
{
"validity": "8 months"
}
And it should update the validity attribute of the item.
Same should apply to any other attribute of the item.
'use strict';
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.update = (event, context, callback) => {
const data = JSON.parse(event.body);
let attr = {};
let nameobj = {};
let exp = 'SET #';
let arr = Object.keys(data);
let attrname = {};
arr.map((key) => {attr[`:${key}`]=data[key]});
arr.map((key) => {
exp += `${key} = :${key}, `
});
arr.map((key) => {nameobj[`#${key}`]=data[key]});
attrname = {
[Object.keys(nameobj)[0]] : nameobj[Object.keys(nameobj)[0]]
}
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: attrname,
ExpressionAttributeValues: attr,
UpdateExpression: exp,
ReturnValues: 'ALL_NEW',
};
// update the todo in the database
dynamoDb.update(params, (error, result) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t update the card',
});
return;
}
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(result.Attributes),
};
callback(null, response);
});
};
Contrary to others comments, this is very possible, use the UpdateItem action.
Language agnostic API docs
JavaScript specific API docs
If you want to dynamically create the query, try something like this:
const generateUpdateQuery = (fields) => {
let exp = {
UpdateExpression: 'set',
ExpressionAttributeNames: {},
ExpressionAttributeValues: {}
}
Object.entries(fields).forEach(([key, item]) => {
exp.UpdateExpression += ` #${key} = :${key},`;
exp.ExpressionAttributeNames[`#${key}`] = key;
exp.ExpressionAttributeValues[`:${key}`] = item
})
exp.UpdateExpression = exp.UpdateExpression.slice(0, -1);
return exp
}
let data = {
'field' : { 'subfield': 123 },
'other': '456'
}
let expression = generateUpdateQuery(data)
let params = {
// Key, Table, etc..
...expression
}
console.log(params)
Output:
{
UpdateExpression: 'set #field = :field, #other = :other',
ExpressionAttributeNames: {
'#field': 'field',
'#other': 'other'
},
ExpressionAttributeValues: {
':field': {
'subfield': 123
},
':other': '456'
}
}
Using Javascript SDK V3:
Import from the right package:
import { DynamoDBClient PutItemCommandInput, UpdateItemCommandInput, UpdateItemCommand } from '#aws-sdk/client-dynamodb';
Function to dynamically do partial updates to the item:
(the code below is typescript can be easily converted to Javascript, just remove the types!)
function updateItem(id: string, item: any) {
const dbClient = new DynamoDBClient({region: 'your-region-here });
let exp = 'set ';
let attNames: any = { };
let attVal: any = { };
for(const attribute in item) {
const valKey = `:${attribute}`;
attNames[`#${attribute}`] = attribute;
exp += `#${attribute} = ${valKey}, `;
const val = item[attribute];
attVal[valKey] = { [getDynamoType(val)]: val };
}
exp = exp.substring(0, exp.length - 2);
const params: UpdateItemCommandInput = {
TableName: 'your-table-name-here',
Key: { id: { S: id } },
UpdateExpression: exp,
ExpressionAttributeValues: attVal,
ExpressionAttributeNames: attNames,
ReturnValues: 'ALL_NEW',
};
try {
console.debug('writing to db: ', params);
const command = new UpdateItemCommand(params);
const res = await dbClient.send(command);
console.debug('db res: ', res);
return true;
} catch (err) {
console.error('error writing to dynamoDB: ', err);
return false;
}
}
And to use it (we can do partial updates as well):
updateItem('some-unique-id', { name: 'some-attributes' });
What i did is create a helper class.
Here is a simple function : Add all the attribute and values that goes into, if the value is null or undefined it won't be in the expression.
I recommande to create a helper class with typescript and add more functions and other stuff like generator of expressionAttributeValues , expressionAttributeNames ... , Hope this help.
function updateExpression(attributes, values) {
const expression = attributes.reduce((res, attribute, index) => {
if (values[index]) {
res += ` #${attribute}=:${attribute},`;
}
return res;
}, "SET ");
return expression.slice(0, expression.length - 1)
}
console.log(
updateExpression(["id", "age", "power"], ["e8a8da9a-fab0-55ba-bae3-6392e1ebf624", 28, undefined])
);
You can use code and generate the params object based on the object you provide. It's just a JavaScript object, you walk through the items so that the update expression only contains the fields you have provided.
This is not really a DynamoDB question in that this is more a general JS coding question.
You can use UpdateItem; to familiarize yourself with DynamoDb queries I would suggest you DynamoDb NoSQL workbench:
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html
It can generate snippets for you based on your queries.
DynamoDb NoSQL workbench screenshot query

Alexa skill forgets session between intents

I'm not sure if it's because I'm testing in the alexa developer console but it appears the session is restarted after every intent.
In the below code, if I invoke SetMyVarA it will write out the correct value to cloudwatch (or the terminal when using serverless), but if I then invoke SetMyVarB immediately after then I'll get "Hmm, I don't know that one" (running locally will just give me undefined for the value).
I've also tried following the advice in this question but it didn't seem to have an effect: adding alexa skill session attributes from nodejs
/*jslint es6 */
"use strict";
const Alexa = require(`alexa-sdk`);
module.exports.handler = (event, context, callback) => {
console.log(`handler: ${JSON.stringify(event.request)}`);
const alexa = Alexa.handler(event, context, callback);
alexa.appId = process.env.APP_ID;
alexa.registerHandlers(handlers);
alexa.execute();
};
const handlers = {
"LaunchRequest": function() {
console.log(`LaunchRequest`);
this.emit(`AMAZON.HelpIntent`);
},
"SetMyVarA": function() {
console.log(`Set MyVarA`);
var myVarA = this.event.session.attributes.myVarA = this.event.request.intent.slots.myVarA.value;
console.log(`MyVarA is ${myVarA}.`);
var speechOutput = `MyVarA has been set to ` + myVarA + `.`;
this.response.speak(speechOutput);
this.emit(`:responseReady`);
},
"SetMyVarB": function() {
console.log(`Set MyVarB`);
var myVarB = this.event.session.attributes.myVarB = this.event.request.intent.slots.myVarB.value;
console.log(`MyVarB is ${myVarB}.`);
var myVarA = this.event.session.attributes.myVarA
console.log(`MyVarA is ${myVarA}.`);
var speechOutput = {
"type": `SSML`,
"ssml": `<speak>MyVarB is ` + myVarB + `.</speak>`,
};
this.response.speak(speechOutput);
this.emit(`:responseReady`);
},
"AMAZON.HelpIntent": function() {
var speechOutput = `This is a skill.`;
var reprompt = `Help here.`;
speechOutput = speechOutput + reprompt;
this.response.speak(speechOutput)
.listen(reprompt);
this.emit(`:responseReady`);
},
"AMAZON.CancelIntent": function() {
},
"AMAZON.StopIntent": function() {
},
"AMAZON.RepeatIntent": function() {
console.log(`RepeatIntent`);
this.emit(`LaunchRequest`);
},
"Unhandled": function() {
// handle any intent in interaction model with no handler code
console.log(`Unhandled`);
this.emit(`LaunchRequest`);
},
"SessionEndedRequest": function() {
// "exit", timeout or error. Cannot send back a response
console.log(`Session ended: ${this.event.request.reason}`);
},
};
In SetMyVar if you use speak() and then emit a responseReady the session gets closed by default, so you're already out of it when you try to call your 2nd intent.
If you want to do exactly the same thing you're doing in SetMyVarA but not close the session immediately you need to set this.response.shouldEndSession to false. The Alexa Dev Console can handle skill sessions with no problems, so don't worry about that.
By the way, you're using ASK v1 which is outdated. Please switch to v2 code like this:
https://developer.amazon.com/blogs/alexa/post/decb3931-2c81-497d-85e4-8fbb5ffb1114/now-available-version-2-of-the-ask-software-development-kit-for-node-js
https://ask-sdk-for-nodejs.readthedocs.io/en/latest/ASK-SDK-Migration-Guide.html

Add a field to Firestore?

I have a field called jobsPosted as seen in the picture, so I want to add another job, I have dishwasher and waiter already. But I get an error with this query
db.collection("companies").doc("Tiradito").field("jobsPosted").set(postJobObject).then(function() {
console.log("Document successfully written!");
});
That's my postJobbject
var postJobObject = {
"position": this.state.selected,
"timeSchedule": this.state.timeSchedule,
"compensation" : this.state.compensation,
"experience" : this.state.experience,
"description" : this.state.description
}
pass the option to merge the new data with any existing document to avoid overwriting entire documents
var cityRef = db.collection('cities').doc('BJ');
var setWithMerge = cityRef.set({
capital: true
}, { merge: true });
source: https://firebase.google.com/docs/firestore/manage-data/add-data
Try
jobsPosted = {}
var postJobObject = {
"position": this.state.selected,
"timeSchedule": this.state.timeSchedule,
"compensation" : this.state.compensation,
"experience" : this.state.experience,
"description" : this.state.description
}
jobsPosted['newJob'] = postJobObject;
Then use update
db.collection("companies").doc("Tiradito").update(jobsPosted).then(function() {
console.log("Document successfully written!");
});

Task timed out after 3.00 seconds - Lambda application with nodeJS

I am trying to put a hard-coded data item to DynamoDB. I am using AWS SDK object to perform this update. And all the debug "Console.log" in the below code is getting printed but eventually it prints Task timed out after 3.00 seconds
With no update to the DynamoDB
function updatedb(intent, session, callback) {
let country;
const repromptText = null;
const sessionAttributes = {};
let shouldEndSession = false;
console.log("In the function");
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-west-1' });
var params = {
TableName: "Location",
Item: {
"LocationID": { "S": "11" },
"Country": { "S": "10" },
"Description": { "S": "10" },
"Name": { "S": "10" }
}
};
console.log("Param loaded & executing the DocClient Put");
docClient.put(params, function (err, data) {
if (err) {
speechOutput = 'Update failed';
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText, shouldEndSession));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
speechOutput = 'Update successful';
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText, shouldEndSession));
}
});
}
The following items are already checked
1) There is a table named "Location" in DynamoDB
2) Both DynamoDB and this lambda function are in ue-west-1 (Ireland)
3) The role assigned for this Lambda function can do all operation on this table. See the policy details below
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1510603004000",
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": [
"arn:aws:dynamodb:eu-west-1:752546663632:table/Location"
]
}
]
}
How does my Lambda function locate the table "location" just with the region?- the code does not appear to have end-point, etc.? - just developed based on a tutorial.
Is that what I am missing?
Please can you help?
I had a similar issue, try putting require statements in the beginning of your function.
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-west-1' });
I believe that AWS locates the table based on your identity, in combination with the region and the table name.
I was able to successfully post to a table using this code:
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({region: 'us-west-2'});
var params = {
TableName: "my-table",
Item: {
"LocationID": { S: "11" },
"Country": { S: "10" },
"Description": { S: "10" },
"Name": { S: "10" }
}
};
dynamoDB.putItem(params, (err, data) => {
if (err){
console.error(err.stack);
} else {
console.log(data);
}
});
If you can in fact post to the table from the CLI, then there is still at least one remaining issue: it appears that you are using the DocumentClient class incorrectly. It looks like you're mixing up the syntax for DynamoDB.putItem with the syntax for DynamoDB.DocumentClient.put.
If you notice, my code uses the DynamoDB class directly-- based on what you're doing, I see no reason why you couldn't do the same. Otherwise, you should change your Item object:
var params = {
TableName: "my-table",
Item: {
"LocationID": "11",
"Country": "10",
"Description": "10",
"Name": "10"
}
};
My guess is your code is currently erroring out because you are trying to insert Maps where you want to insert Strings. If you have Cloudwatch configured you could check the logs.
Finally, I don't see you using callback in your code. If your intention is to respond to a client calling the lambda you should do that. Depending on your NodeJS version, the lambda can simply time out without returning a useful response.

Meteor query sort error "Requests.find(...).sort is not a function"

I need to sort "datetime" ascending format. But getting an error "Requests.find(...).sort is not a function" meteor mini mongo find
var results = Requests.find({
"sp_id": request.sp_id,
"slot": request.slot,
"date": request.date,
"datetime": {
'$gte': request.datetime
},
"status": {
$nin: ['cancel', 'completed']
}
}
).sort({datetime: 1}).fetch();
console.log(results);
Thanks.
The syntax would be:
const query = { your: 'query' };
const options = { sort: { datetime: 1 } };
const results = Requests.find(query, options).fetch();
Have a look at the docs.

Resources