How do you query DynamoDB - amazon-web-services

I'm on Step 5.1 of "DynamoDB's Getting Started guide" http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.JsShell.05.html#GettingStarted.JsShell.05.01 and am blocked by a non-working example.
var params = {
TableName: "Music",
KeyConditionExpression: "Artist = :artist",
ExpressionAttributeValues: {
":artist": "No One You Know"
}
};
dynamodb.query(params, function(err, data) {
if (err)
console.log(JSON.stringify(err, null, 2));
else
console.log(JSON.stringify(data, null, 2));
});
The shell accepts the input but produces an Error
{
"message": "There were 2 validation errors:\n* MissingRequiredParameter: Missing required key 'KeyConditions' in params\n* UnexpectedParameter: Unexpected key 'KeyConditionExpression' found in params",
"code": "MultipleValidationErrors",
"errors": [
{
"message": "Missing required key 'KeyConditions' in params",
"code": "MissingRequiredParameter",
"time": "2015-10-27T03:08:56.504Z"
},
{
"message": "Unexpected key 'KeyConditionExpression' found in params",
"code": "UnexpectedParameter",
"time": "2015-10-27T03:08:56.504Z"
}
],
"time": "2015-10-27T03:08:56.504Z"
}
I tried sub'ing in 'KeyConditions' for 'ExpressionAttributeValues' like...
var params = {
TableName: "Music",
KeyConditionExpression: "Artist = :artist",
KeyConditions: {
":artist": "No One You Know"
}
};
dynamodb.query(params, function(err, data) {
if (err)
console.log(JSON.stringify(err, null, 2));
else
console.log(JSON.stringify(data, null, 2));
});
...but that just produces empty results {}. There are, of course, items in "Music" with the "Artist" attribute set to "No One You Know", so I'm kind-of lost how to proceed here.
What is the correct expression to query DDB for the value "No One You Know" in the Artist attribute?

The root cause of this is a stale "dynamodb-local" installation. brew upgrade dynamodb-local deployed a 2015-07-16_1.0 version of this kid and the query now works.

Related

DynamoDB Scan for a nested attribute values with NodeJS

I have a DynamoDB with nested values inside.
An Entry looks like the following:
Now I would like to scan all entries in the database to find all entries with a specific episodeGuid.
I tried this code (and some variants), but always with 0 results.
var params = {
TableName: "myTableName",
FilterExpression: "#episodeGuid = :myEpisode",
ExpressionAttributeNames: {
'#episodeGuid': 'attributes.playbackInfo.episodeGuid',
},
// ExpressionAttributeValues: { ":myEpisode": { "S": "podlove-2018-12-06t13:07:10+00:00-f8a9b2963f313e5" } }
ExpressionAttributeValues: { ":myEpisode": "podlove-2018-12-06t13:07:10+00:00-f8a9b2963f313e5" }
};
oDynamoDBClient.scan(params, async function (err, data) {
console.log('read return');
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data);
}
});
Can someone give me a hint how can I find my entries?
The filter is looking for an attribute named attributes.playbackInfo.episodeGuid as opposed to a nested attribute.
To look for a nested attribute, the expression needs to contain to ..
FilterExpression: "#attributes.#playbackInfo.#episodeGuid = :myEpisode",
ExpressionAttributeNames: {
'#attributes': 'attributes',
'#playbackInfo': 'playbackInfo',
'#episodeGuid': 'episodeGuid',
},

DynamoDB update list of list items

I need your help to update/add item in a list of list of DynamoDB.
I want to add and update a list that is composed by a list.
How can i do that? Thanks for your help
Here my example:
DATABASE
Item{1}
idProject:"15azeze-55ze"
dateCreationProjectString: 08/01/2018 14:6:32
environnements: List[1]
0 MAP {3}
idEnvironnement: "11-aa",
name:"Exemple Environnement"
tasks[0]
NodeJS code :
let newTask = {
authorTask : "Toto",
dateCreationTask: "01/01/1960",
idTask: "154-141-aa41",
nameTask: "Task name ..."
};
dynamodbdc.update({
TableName: "projects",
Key: { idProject: "15azeze-55ze", idEnvironnement:"11-aa" },
ReturnValues: 'ALL_NEW',
UpdateExpression: 'set #environnements.#tasks = list_append(if_not_exists(#environnements.#tasks, :empty_list), :newTask)',
ExpressionAttributeNames: {
'#environnements' : 'environnements',
'#tasks' : 'tasks',
},
ExpressionAttributeValues: {
':newTask': [newTask],
':empty_list': []
}
}, function(error, stdout) {
if(error){
console.log("error==", error)
else {
console.log("Nice thank you !!")
}
});
I would suggest to keep the tasks attribute as SET ('SS') which will simplify to NOT add the duplicate values. Otherwise, it would be difficult to fulfil the scenario.
Also, you may the index of the environments attribute list to form the update expression correctly. There is no options in the dynamodb api to workout the index automatically.
The below code should work if you define the tasks attribute as SET.
Insert item code:-
var params = {
TableName : table,
Item : {
"idProject" : "15azeze-55ze",
"dateCreationProjectString" : Date(),
"environnements" : [{
"idEnvironnement" : "11-aa",
"name" : "Example Environments",
"tasks" : docClient.createSet(["1"])
}]
}
};
console.log("Adding a new item...");
docClient.put(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err,
null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
Sample update item working code:-
The ADD operation will ensure that it doesn't add duplicates to the SET
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "projects",
Key: {
"idProject" : "15azeze-55ze"
},
UpdateExpression: 'ADD environnements['+0+'].tasks :tasksVal',
ExpressionAttributeValues: {
":tasksVal": docClient.createSet(["2"])
},
ReturnValues: "UPDATED_NEW"
};
console.log("Updating the item...");
docClient.update(params, function (err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data));
}
});

"Converting circular structure to JSON" while reading data from MYSQL and putting it in DynamoDB

I am reading data from read replica of Aurora and putting it into the DynamoDB. I getting data from RDS correctly but facing problems while inserting it into DynamoDB. I am sharing my code and error message please guide me....
var AWS = require("aws-sdk");
var mysql = require('mysql');
const client = new AWS.DynamoDB.DocumentClient({region : 'eu-west-1'});
var connection = mysql.createPool({
host : "**********",
user : "****",
password : "*****",
database : "mydb",
port : "3306"
});
exports.handler = (event, context, callback) => {
connection.query('select * from demo where id=2;', function (error, results, fields) {
if (error) {
if (error) throw error;
} else {
var data = {results};
var params = {
Item:{
test_id:data.id,
name:data.name,
result:data.result
},
TableName: 'demo_rds_dynamoDB'
};
connection.end(function (err) {
callback(err, client.put(params, function(error,data){
if(error){
callback(error,null);
}else{
callback(null,data);
}
})
);
});
}
});
};
Following is the data I am getting from Aurora and I want to put in DynamoDB
Response:
[
{
"id": 2,
"name": "Display",
"result": "Pass"
}
]
And the response m getting is as follow and sometimes i get error as Cannot read property "id" undefined,
Response:
{
"errorMessage": "Converting circular structure to JSON",
"errorType": "TypeError",
"stackTrace": []
}
Request ID:
"896a64e3-573e-11e8-bb94-67c4be71eb3d"
Function Logs:
START RequestId: 896a64e3-573e-11e8-bb94-67c4be71eb3d Version: $LATEST
Unable to stringify response body as json: Converting circular structure to JSON: TypeError
at Object.stringify (native)
Item:{
test_id:results[0].id,
name:results[0].name,
result:results[0].result
}
results[0].columnname

Searching DynamoDB for non primary keys and integrating into Alexa Skills

I am trying to search a non primary key using AWS Lambda and integrating it into the Alexa Skills Kit. I am very new to using DynamoDB and Alexa Skills Kit and I'm struggling to find any solutions to this online. The basic premise for what I am trying to do is querying the table yesno with two columns, id and message. Only looking through the message column to find a match with the text i specify in params.
Here is the Lambda code I am working with:
const AWSregion = 'eu-west-1';
const Alexa = require('alexa-sdk');
const AWS = require('aws-sdk');
//params for searching table
const params = {
TableName: 'yesno',
Key:{ "message": 'Ben Davies' }
};
AWS.config.update({
region: AWSregion
});
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
// alexa.appId = 'amzn1.echo-sdk-ams.app.1234';
// alexa.dynamoDBTableName = 'YourTableName'; // creates new table for session.attributes
alexa.registerHandlers(handlers);
alexa.execute();
};
const handlers = {
'LaunchRequest': function () {
this.response.speak('welcome to magic answers. ask me a yes or no question.').listen('try again');
this.emit(':responseReady');
},
'MyIntent': function () {
var MyQuestion = this.event.request.intent.slots.MyQuestion.value;
console.log('MyQuestion : ' + MyQuestion);
readDynamoItem(params, myResult=>{
var say = MyQuestion;
say = myResult;
say = 'you asked, ' + MyQuestion + '. I found a reckord for: ' + myResult;
this.response.speak(say).listen('try again');
this.emit(':responseReady');
});
},
'AMAZON.HelpIntent': function () {
this.response.speak('ask me a yes or no question.').listen('try again');
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak('Goodbye!');
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak('Goodbye!');
this.emit(':responseReady');
}
};
// END of Intent Handlers {} ========================================================================================
// Helper Function =================================================================================================
function readDynamoItem(params, callback) {
var AWS = require('aws-sdk');
AWS.config.update({region: AWSregion});
var dynamodb = new AWS.DynamoDB();
console.log('reading item from DynamoDB table');
dynamodb.query(params, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
console.log(data); // successful response
callback(data.Item.message);
}
});
}
I know I am probably doing this completely wrong but there isn't much online for integrating DynamoDB with an Alexa Skill and the only thing i was able to find was searching by ID. This doesn't work for what i want to do without pulling all the items from the table into a map or a list, and seeing as I want to create a big database it seems quite inefficient.
On the Alexa side of things I am receiving the following service request when testing the code:
{
"session": {
"new": true,
"sessionId": "SessionId.f9558462-6db8-4bf5-84aa-22ee0920ae95",
"application": {
"applicationId": "amzn1.ask.skill.9f280bf7-d506-4d58-95e8-b9e93a66a420"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AF5IJBMLKNE32GEFQ5VFGVK2P4YQOLVUSA5YPY7RNEMDPKSVCBRCPWC3OBHXEXAHROBTT7FGIYA7HJW2PMEGXWHF6SQHRX3VA372OHPZZJ33K7S4K7D6V3PXYB6I72YFIQBHMJ4QGJW3NS3E2ZFY5YFSBOEFW6V2E75YAZMRQCU7MNYPJUMJSUISSUA2WF2RA3CIIDCSEY35TWI"
}
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.7310073b-981a-41f8-9fa5-03d1b28c5aba",
"intent": {
"name": "MyIntent",
"slots": {
"MyQuestion": {
"name": "MyQuestion",
"value": "erere"
}
}
},
"locale": "en-US",
"timestamp": "2018-01-25T14:18:40Z"
},
"context": {
"AudioPlayer": {
"playerActivity": "IDLE"
},
"System": {
"application": {
"applicationId": "amzn1.ask.skill.9f280bf7-d506-4d58-95e8-b9e93a66a420"
},
"user": {
"userId": "amzn1.ask.account.AF5IJBMLKNE32GEFQ5VFGVK2P4YQOLVUSA5YPY7RNEMDPKSVCBRCPWC3OBHXEXAHROBTT7FGIYA7HJW2PMEGXWHF6SQHRX3VA372OHPZZJ33K7S4K7D6V3PXYB6I72YFIQBHMJ4QGJW3NS3E2ZFY5YFSBOEFW6V2E75YAZMRQCU7MNYPJUMJSUISSUA2WF2RA3CIIDCSEY35TWI"
},
"device": {
"supportedInterfaces": {}
}
}
},
"version": "1.0"
}
And I am receiving a service response error simply saying 'The response is invalid'
Any help with this would be greatly appreciated
I would like to help you in dynamo db part.
In order to access non primary key columns in dynamodb you should perform scan operation.
For your table (yesno), id is a primary key and message is an additional column.
Snippet to access non primary key column [Message]
var dynamodb = new AWS.DynamoDB();
var params = {
TableName: 'yesno',
FilterExpression: 'message = :value',
ExpressionAttributeValues: {
':value': {"S": "Ben Davies"}
}
};
dynamodb.scan(params, function(err, data) {
if (err) // an error occurred
else console.log(data); // successful response
});
Snippet to access primary key column [Id]
var docClient = new AWS.DynamoDB.DocumentClient();
//Get item by key
var params = {
TableName: 'sis_org_template',
Key: { "id": "1"}
};
docClient.get(params, function(err, data) {
if (err) // an error occurred
else console.log(data); // successful response
});

before Remote in Loopback

I'm trying to use the before Remote hook in loopback to check an user token before the call of my remote method, but the thing is that I can only return a javascript Error, like these.
"error": {
"statusCode": 401,
"name": "Error",
"message": ""
}
This is the code that i'm using in the before remote.
Model.beforeRemote('method', function (context, unused, next) {
let token = Model.app.models.Token;
let id = context.args.Id;
let date = moment();
Rx.Observable.fromPromise(token.find({
where: {
and: [
{ id: id, },
{ expiration: { gt: date } }
]
}
})).subscribe((token => {
if (token.length > 0) {
next();
} else {
let err = new Error();
err.status = 401;
delete err.stack;
return next()
}
}))
});
And I need a "custom" response that isn't an error, something like these.
{
"success": false,
"data": {
"service": "self",
"operation": "rest",
"code": "unauthorized"
},
"message": "Invalid token"
}
I tried with the after Remote hook and I can change the response to get something like that, but I want to get a quicker response in the case that the token is invalid.
Is there any way to achieve this with the before hook? or I had to use after hook?
Thanks
You may want to pass the error to the next function:
return next(err)