Why is dynamodb.update() is not updating the field in my Table? - amazon-dynamodb

I have a dynamodb Table named "user_subscription", I want to update the status field from "ACTIVE" to "INACTIVE",
const params = {
TableName: "user_subscription",
Key: {
userId: userId,
subscription_id: "abc",
},
updateExpression: "SET status = :newStatus",
expressionAttributeValues: { ":newStatus": "INACTIVE" },
ReturnValues: "ALL_NEW",
};
console.log("params", params);
try {
dynamoDb.update(params, (error, data) => {
console.log("error", error, "data", data);
});
} catch (err) {}
This code doesn't update the status field.
The response data which I get is:
Attributes: {
plan_id: 'dkdkkd',
subscription_id: 'abc',
userId: 'ebef4c92-9fa8-4e1b-878f-d5753bb4042a',
updatedAt: '2022-12-25T08:18:32.681Z',
status: 'ACTIVE',
createdAt: '2022-12-25T08:18:32.681Z'
}

Status is a reserved keyword in DynamoDB, I believe the code you shared should be throwing several errors, are you sure you are executing the correct code while testing?
To fix your errors, try these params:
const params = {
TableName: "user_subscription",
Key: {
userId: userId,
subscription_id: "abc",
},
UpdateExpression: "SET #status = :newStatus",
ExpressionAttributeValues: { ":newStatus": "INACTIVE" },
ExpressionAttributeNamee: { "#status": "status" },
ReturnValues: "ALL_NEW",
};

Related

when Updating items in DynamoDB giving error Invalid UpdateExpression using NodeJS

This is my handler function.
const updateOrder = (request) => {
const id = request.pathParams.id;
const orderObject = request.body;
if(!id || !orderObject)
throw new Error ('Please provide required id and object in order to update the order')
const params = {
TableName: "pizza-order",
Key: {
"orderId": id
},
UpdateExpression: "SET #n = :n, #a = :a ",
ExpressionAttributeNames: {
"#n": "pizza",
"#a": "address"
},
ConditionExpression: '' ,
ExpressionAttributeValues: {
":n": orderObject.pizza,
":a": orderObject.address,
},
};
return docClient.update(params).promise()
}
And the order Object is:
{
"pizza":"THe outstanding pizza",
"Address": "feni"
}
And it returns error like this. I don't know why it is happening. Very new to serverless development. anyone know the solution?
It was a very silly mistake. First in the order Object there is a typo:
{
"pizza":"THe outstanding pizza",
"address": "feni" //previously it was Address: "feni
}
And the second reason is ConditionExpression Can not be empty.
const updateOrder = (request) => {
const id = request.pathParams.id;
const orderObject = request.body;
if(!id || !orderObject)
throw new Error ('Please provide required id and object in order to update the order')
const params = {
TableName: "pizza-order",
Key: {
"orderId": id
},
UpdateExpression: "SET #n = :n, #a = :a ",
ExpressionAttributeNames: {
"#n": "pizza",
"#a": "address"
},
ConditionExpression: '' , // this can not be empty
ExpressionAttributeValues: {
":n": orderObject.pizza,
":a": orderObject.address,
},
};
return docClient.update(params).promise()
}

Add a number to a list item with DynamoDB

This is the DynamoDB table structure I'm working on:
{
"userId": "99999999-9999-9999-9999-999999999999",
"userProfile": {
"email": "myemail#gmail.com",
"firstName": "1234124",
"lastName": "123423",
},
"masterCards": [
{
"cardId": 101000000000001,
"cardImage": "logo.png",
"cardName": "VipCard1",
"cardWallet": "0xFDB17d12057b6Fe8c8c425D2DB88d8475674567"
},
{
"cardId": 102000000000002,
"cardImage": "logo.png",
"cardName": "VipCard2",
"cardWallet": "0xFDB17d12057b6Fe8c8c425D2DB88d8183454345"
},
{
"cardId": 103000000000003,
"cardImage": "logo.png",
"cardName": "VipCard3",
"cardWallet": "0xFDB17d12057b6Fe8c8c425D2DB88d8184345345"
}
],
}
I'm trying to increase the cardId field by one for the first list item with this Lambda function:
const dynamoDB = new AWS.DynamoDB({region: 'eu-central-1', apiVersion:'2012-08-10'});
const counterId="99999999-9999-9999-9999-999999999999"
const params = {
TableName:"FidelityCardsUsers",
Key: {"userId":{"S":counterId}},
UpdateExpression:"ADD #masterCards[0].#cardId :increment",
ExpressionAttributeNames:{
"#masterCards": "masterCards",
"#cardId": "cardId"
},
ExpressionAttributeValues:{":increment": {"N": "1"}}
}
dynamoDB.updateItem(params, function(err, data) {
if (err) {
console.log('error getting counter from DynamDB: ',err)
callback(err);
} else {
callback(null,data)
}
})
In return I get only a new top-level attribute named "mastercards[0].cardId[0]" with a value number set to 1.
I have tried to increment In an array and its work fine with AWS.DynamoDB.DocumentClient()
Example :
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
let params = {
TableName:'tableName',
Key: {
'venueId': 'VENUE_002'
},
UpdateExpression: "ADD #walk.#coordinates[0] :increment",
ExpressionAttributeNames: {
'#walk': 'walk',
'#coordinates': 'coordinates'
},
ExpressionAttributeValues: {
':increment': 1 // This is from the client
},
ReturnValues: 'UPDATED_NEW'
};
docClient.update(params, function (err, data) {
if (err) {
console.log('failure:updateShuttleDirection:failed');
console.log(err);
} else {
console.log('success:updateShuttleDirection:complete');
console.log(data);
}
});
Sample Data:
"walk": {
"coordinates": [
10,
20
],
"type": "Point"
},
I have tried to increment 10 to 11 and its work fine
Reading the doc here, it seems that:
the ADD action can only be used on top-level attributes, not nested
attributes.

The provided key element does not match the schema - updateItem

var params = {
ExpressionAttributeNames: {
"#AT": "date"
},
ExpressionAttributeValues: {
":t": {
BOOL: false
}
},
Key: {
"#AT": {
N: data.Items[i].date.N
},
"accountid": {
S: data.Items[i].accountid.S
}
},
ReturnValues: "ALL_NEW",
TableName: "tab",
UpdateExpression: "SET #AT = :t"
}
db.updateItem(params, function (err, data) {
if (err) console.log(err);
else {
//console.log(data);
}
});
What is happening is that the code is not working. It gives me this error:
message: 'The provided key element does not match the schema'
This is what is in table details:
Primary partition key - date (Number)
Primary sort key -
The problem is that you've got a composite key (date + accountid) in your params, but your table is only configured with a partition key.
Either use this:
var params = {
ExpressionAttributeValues: {
":t": { BOOL: false }
},
ExpressionAttributeNames: {
"#at": "isRelevant",
},
Key: {
"date": { N: data.Items[i].date.N }
},
ReturnValues: "ALL_NEW",
TableName: "tab",
UpdateExpression: "SET #at = :t"
}
db.updateItem(params, function (err, data) {
if (err) {
console.log(err);
} else {
//console.log(data);
}
});
Or, if you expected to use accountid as a sort key, then you'll need to rebuild your table.

How to create and populate lists in DynamoDB

I wish to create an Item in DynamoDB that is a list. This is my code:
var list_update_params = {
TableName: "table01",
Key: {
"MachineID": {
"S": MachineID
},
"Hour": {
"S": Hour
}
},
UpdateExpression: "set var01_list = list_append(var01_list, :ot)",
ExpressionAttributeValues: {
":ot": {"L": [{"N": var01}]}
},
ReturnValues: "NONE"
};
dynamodb.updateItem(list_update_params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log("Updated List to DynamoDB");
});
The problem is list_append expects the attribute var01_list to already be present, but I wouldn't know at the first insert. Is there a technique where it'll let me create an insert a List attribute if one doesn't exist and append to it in later calls?
Got the answer from a similar post here.
UpdateExpression: "set var01_list= list_append(if_not_exists(var01_list, :empty_list), :h)",
ExpressionAttributeValues: {
":h": {"L": [{"N":var01}]},
":empty_list": {"L": []}
},
The key was using if_not_exists with list_append. Didn't know that could be done in this matter

Apollo/GraphQL: Setting Up Resolver for String Fields?

In GraphiQL at http://localhost:8080/graphiql, I'm using this query:
{
instant_message(fromID: "1"){
fromID
toID
msgText
}
}
I'm getting this response:
{
"data": {
"instant_message": {
"fromID": null,
"toID": null,
"msgText": null
}
},
"errors": [
{
"message": "Resolve function for \"instant_message.fromID\" returned undefined",
"locations": [
{
"line": 3,
"column": 5
}
]
},
{
"message": "Resolve function for \"instant_message.toID\" returned undefined",
"locations": [
{
"line": 4,
"column": 5
}
]
},
{
"message": "Resolve function for \"instant_message.msgText\" returned undefined",
"locations": [
{
"line": 5,
"column": 5
}
]
}
]
}
I tried to set up my system according to the examples found here:
https://medium.com/apollo-stack/tutorial-building-a-graphql-server-cddaa023c035#.s7vjgjkb7
Looking at that article, it doesn't seem to be necessary to set up individual resolvers for string fields, but I must be missing something.
What is the correct way to update my resolvers so as to return results from string fields? Example code would be greatly appreciated!
Thanks very much in advance to all for any thoughts or info.
CONNECTORS
import Sequelize from 'sequelize';
//SQL CONNECTORS
const db = new Sequelize(Meteor.settings.postgres.current_dev_system.dbname, Meteor.settings.postgres.current_dev_system.dbuser, Meteor.settings.postgres.current_dev_system.dbpsd, {
host: 'localhost',
dialect: 'postgres',
});
db
.authenticate()
.then(function(err) {
console.log('Connection to Sequelize has been established successfully.');
})
.catch(function (err) {
console.log('Unable to connect to the Sequelize database:', err);
});
const IMModel = db.define('IM', {
id: {type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true},
fromID: {type: Sequelize.STRING},
toID: {type: Sequelize.STRING},
msgText: {type: Sequelize.STRING}
});
IMModel.sync({force: true}).then(function () {
// Table created
return IMModel.create({
fromID: '1',
toID: '2',
msgText: 'msg set up via IMModel.create'
});
});
const IM = db.models.IM;
export {db, IM };
SCHEMA
const typeDefinitions = [`
type instant_message {
id: Int
fromID: String
toID: String
msgText: String
}
type Query {
instant_message(fromID: String, toID: String, msgText: String): instant_message
}
type RootMutation {
createInstant_message(
fromID: String!
toID: String!
msgText: String!
): instant_message
}
schema {
query: Query,
mutation: RootMutation
}
`];
export default typeDefinitions;
RESOLVERS
import * as connectors from './db-connectors';
import { Kind } from 'graphql/language';
const b = 100;
const resolvers = {
Query: {
instant_message(_, args) {
const a = 100;
return connectors.IM.find({ where: args });
}
},
RootMutation: {
createInstant_message: (__, args) => { return connectors.IM.create(args); },
},
};
export default resolvers;
When you define your GraphQLObjectTypes you need to provide a resolver for each of their fields.
You defined your instant_message with multiple fields but did not provide resolvers for each of these fields.
More over you defined the types of those field with regular typescript fields while you need to define it with GraphQL types (GraphQLInt, GraphQLString, GrapQLFloat etc..)
So defining your type should look something like this:
let instant_message = new GraphQLObjectType({
id: {
type: GraphQLInt,
resolve: (instantMsg)=> {return instantMsg.id}
}
fromID: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.fromID}
}
toID: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.toID}
}
msgText: {
type: GraphQLString,
resolve: (instantMsg)=> {return instantMsg.msgText}
}
})
In addition, you will need to define your Query as follows:
let Query = new GraphQLObjectType({
name: "query",
description: "...",
fields: () => ({
instant_messages: {
type: new GraphQLList(instant_message),
args: {
id: {type: GraphQLInt}
},
resolve: (root, args) => {
connectors.IM.find({ where: args })
}
}
})
})
The issue is that the query does not expect an array,
Please fix it:
type Query {
instant_message(fromID: String, toID: String, msgText: String): [instant_message]
}
Then you should make sure the resolver returns Array of objects, if it doesnt work then the resolver is not returning an Array.

Resources