Problem with query on nested attribute DynamoDB - node.js

In my code I'm using the AWS.DynamoDB.DocumentClient() for interact with the DB.
My item structure is:
{
"docName": "drinkDoc",
"sortKey": "RISTRETTO",
"i18n": {
"de": "",
"en": "ristretto",
"fr": "",
"it": "ristretto"
},
"params": {
"size": [
"S",
"M",
"L",
"XL"
]
}
}
What I want to do is to retrieve the item filtering by i18n subproperties.
In my code I build a params object like this:
{
"TableName": "MyTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n.it"
},
"ExpressionAttributeValues": {
":docName": "drinkDoc",
":drinkName": "ristretto"
},
"FilterExpression": "#i18n = :drinkName"
}
Then I execute the query in this way:
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.query(params, (err, data) => {
if (err) {
console.error("Unable to retrieve data. Error JSON:", JSON.stringify(err, null, 2));
return reject(JSON.stringify(err, null, 2));
}
console.log("Read data succeeded:", JSON.stringify(data, null, 2));
resolve(data.Items);
});
So far so good.
The problem is that the query returns no item, but item exists in my database, as you can see:
What is wrong in this snippet?

I solved from my self.
As indicated in this link https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html
the code
{
"TableName": "MyTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n.it"
},
"ExpressionAttributeValues": {
":docName": "drinkDoc",
":drinkName": "ristretto"
},
"FilterExpression": "#i18n = :drinkName"
}
must be replaced with
{
"TableName": "SmartCoffeeSkillTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n",
"#locale": "it"
},
"ExpressionAttributeValues": {
":docName": "drinks",
":drinkName": "caffè"
},
"FilterExpression": "#i18n.#locale = :drinkName"
}
that is to replace
"FilterExpression": "#i18n = :drinkName" with "FilterExpression": "#i18n.#locale = :drinkName"

Related

NodeJS + mongoDB findOneAndUpdate array of array

i have a collection like this:
{
"_id": {
"$oid": "5ef51c1b8433890012d99ce6"
},
"setor": ["Escrita Fiscal", "Gerência"],
"atendendo": true,
"chatId": "5544999990#c.us",
"senderName": "Victor Barbieri",
"tel": "(44)9949-9999",
"avatarImg": "url",
"mensagens": [{
"author": "554499493950#c.us",
"time": 1593121828,
"fromMe": true,
"horarioBR": "25/06/2020, 18:50",
"body": "```💼 INICIANDO ATENDIMENTO```\nBoa Tarde, Me chamo *Victor Barbieri*, em que podemos lhe ajudar hoje ?",
"caption": null,
"quotedMsgBody": null,
"seen": true
}, {
"author": "5544999990#c.us",
"time": 1593121829,
"fromMe": true,
"horarioBR": "25/06/2020, 18:50",
"body": "*[Victor.B]* 32",
"caption": null,
"quotedMsgBody": null,
"seen": true
}, {
"author": "5544999990#c.us",
"time": 1593121834,
"fromMe": false,
"horarioBR": "25/06/2020, 18:50",
"body": "Frio",
"caption": null,
"quotedMsgBody": null,
"seen": false
}]
}
Using NodeJS im trying to update the last object of mensagens with column seen to true , i tried using findOneAndUpdate but im relative new to mongodb and nodejs, i cant get the "logic" for it..
My idea was to sort mensagens by time (it is a unix time) so i can get the newest message and after get the newest message i can update the seen column to true..
what im missing ?
sorry for my bad english :/
I have something like this now:
return new Promise(function (resolve, reject) {
db.db("intranet")
.collection(ATTABERTO_COLECTIONS)
.findOneAndUpdate(
{ chatid: req.body.chatid },
{ $set: { mensagens: { "mensages.seen": req.body.seen } } },
{
sort: { "mensagens.time": -1 }
}, function (err, r) {
if (err) reject(r);
else {
mensagem = {
seen: req.body.seen
};
avisarFrontEnd(mensagem);
resolve(r);
}
}
);

Updating dynamoDB from Lambda function failed

I've got a problem updating DynamoDB entry.
The DB looks like this
{
"userId":"amzn1.ask.account.XYZ",
"mapAttr":{
"name":"John",
"colors":[
"yellow",
"white"
]
}
}
I want to update the List of colors utilizing follwoing code:
var docClient = new AWS.DynamoDB.DocumentClient({ apiVersion: "2012-08-10" });
var params = {
TableName: "myTable",
Key: {
userId: userId
},
UpdateExpression: "SET #mapAttr = list_append(#mapAttr, :entry)",
ExpressionAttributeNames: { "#mapAttr": "mapAttr.colors" },
ExpressionAttributeValues: {
":entry": ["blue"]
},
ReturnValues: "UPDATED_NEW"
};
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, null, 2));
}
});
and i get the following message:
Unable to update item. Error JSON: { "message": "The provided key
element does not match the schema", "code": "ValidationException",
Any ideas why... ?
Per AWS documentation, you need to split your ExpressionAttributeNames up.
UpdateExpression: "SET #mapAttr.#colors = list_append(#mapAttr.#colors, :entry)",
ExpressionAttributeNames: {
"#mapAttr": "mapAttr",
"#colors": "colors"
}

node.js: DynamoDB DocumentClient returning empty object

I am using DynamoDB local and can create and delete table. I created a table with only one key like below
const tablePromise = dynamodb.listTables({})
.promise()
.then((data) => {
const exists = data.TableNames
.filter(name => {
return name === tableNameLogin;
})
.length > 0;
if (exists) {
return Promise.resolve();
}
else {
const params = {
TableName: tableNameLogin,
KeySchema: [
{ AttributeName: "email", KeyType: "HASH"}, //Partition key
],
AttributeDefinitions: [
{ AttributeName: "email", AttributeType: "S" },
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10
}
};
dynamodb.createTable(params, function(err, data){
if (err) {
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
}
});
Now I want to insert an item in the table following example doc at AWS.
var docClient = new AWS.DynamoDB.DocumentClient();
var tableNameLogin = "Login"
var emailLogin = "abc#gmail.com";
var params = {
TableName:tableNameLogin,
Item:{
"email": emailLogin,
"info":{
"password": "08083928"
}
}
};
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));
}
});
When I run the insert item code, I get Added item: {} Why does it output an empty object? Is it actually inserting anything? I looked into this callback example but this time it doesn't output anything.
You need to add ReturnValues: 'ALL_OLD' to your put params. It will look like as mentioned below.
var params = {
TableName:tableNameLogin,
Item:{
"email": emailLogin,
"info":{
"password": "08083928"
}
},
ReturnValues: 'ALL_OLD'
};
For more details, you can follow this https://github.com/aws/aws-sdk-js/issues/803

Remove nested attribute in dynamodb

Let's say I have this item in DynamoDB:
{
"customerId": "customer_001",
"customerName": "itsme",
"address": {
"city": "Frankfurt",
"country": "Germany",
"street1": "c/o Company xxx",
"street2": "Europe",
"street3": "PO Box 406",
"zip": "12345"
}
}
I need to remove the nested attribute address.street3 from the item. How I can accomplish this?
Here is my code below; it works perfectly to remove non-nested attributes (for example, customerName), but if I try to use this in nested attributes (like address.street3), it silently fails.
const params = {
TableName: customerTable,
Key: {
customerId: customerId,
},
AttributeUpdates: {
'address.street3':
{
Action: 'DELETE'
}
}
};
dynamoDb.update(params, function (err, data) {
if (err) {
console.error("Unable to update customer. Error JSON:", JSON.stringify(err, null, 2));
}
else {
console.log("UpdateCustomer succeeded:", JSON.stringify(data.Attributes));
responseHelper.ResponseHelper.success(JSON.stringify(data.Attributes), 200, callback);
}
});
What can I remove the nested attribute address.street3?
Here is the code to remove "address.street3" attribute.
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName : "customer",
Key : {
"customerId": "customer_001"
},
UpdateExpression : "REMOVE address.street3",
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));
}
});

DynamoDB putitem in NodeJs - arrays of objects

I'm trying to set up a small api from AWS Lambda to DynamoDB and I am having trouble figuring out if and how I can write an array of objects into a key.
I have an object like
{
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
The members array is giving me issues, in the docs it looks like it can be done considering the list types, but there is just no example how HOW to do it, and I am running out of ways to try it.
So is it possible to write something in this format at all and how do you in that case do it?
Example code - what do I put at ???
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();
exports.handler = function(event, context) {
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
DynamoDB.putItem({
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": ???
}
});
}
The documentation is not really obvious, but there is a thing called DocClient, you can pass a usual JS object to it and it will do all the parsing and transformation into AWS object (with all the types). You can use it like this:
var AWS = require("aws-sdk");
var DynamoDB = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "MyTable",
Item: {
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
};
DynamoDB.put(params, function (err) {
if (err) {
return throw err;
}
//this is put
});
You could convert the object to DynamoDb record first
const AWS = require('aws-sdk');
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
const members = [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
];
const marshalled = AWS.DynamoDB.Converter.marshall({ members });
const params = {
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": marshalled.members,
},
}
AWS.DynamoDB.putItem(params, function (err) {
if (err) {
return throw err;
}
});

Resources