Below is a sample item object/record stored in DynamoDb. I use NodeJS and AWS.DynamoDB.DocumentClient to access the database.
I'm building out a PUT function to update the status for an JSON object in an array. The function will have access to the Item's uuid and room's uuid. How can I simply (creatively) update the value of corresponding status field, given the array of JSON objects?
Params:
let params = {
TableName: room-table,
Key: {
uuid: event.body.uuid
},
UpdateExpression : "??",
ExpressionAttributeNames: {
"??":"??"
},
ExpressionAttributeValues:{
"??":"??"
},
ReturnValues:"ALL_NEW"
};
Item Object:
{
"Item": {
"uuid": "77b1e88e-5e60-44d9-b6ca-aec345c0dc99",
"rooms": [
{
"room": "303",
"status": "pending",
"uuid": "b8f1c1a8-04a9-4c2e-82ad-bc3e81face35"
},
{
"room": "302",
"status": "pending",
"uuid": "42fdc61a-4a25-4316-90c9-60209875d208"
},
{
"room": "678",
"status": "pending",
"uuid": "7bedc115-20ed-4c3e-9cd7-7fed0520f4df"
}
],
"status": "pending"
}
}
It's not possible to do this with ExpressionAttributeValues. I had to build a function to modify the object, similar to below:
function setStatus(jsonObj, uuid, newStatus) {
for (var i=0; i<jsonObj.length; i++) {
if (jsonObj[i].uuid === uuid) {
jsonObj[i].status = newStatus;
return jsonObj;
}
}
}
let params = {
TableName: room-table,
Key: {
uuid: event.body.uuid
},
UpdateExpression : "SET #stat = :stat",
ExpressionAttributeNames: {
"#stat": "status"
},
ExpressionAttributeValues:{
":stat": "updatedStatusValue"
},
ReturnValues:"ALL_NEW"
};
ExpressionAttributeNames is needed because status is a DynamoDB reserved word. More info on Attribute Name and Attribute Value placeholders is available in the DynamoDB docs.
Related
Trying to be able to filter on embedded object that looks like:
"posts": [
{
"id": "10e85cf7-acd2-417b-a5dc-1dfb6de606bf",
"references": [
{
"type": "URL",
"title": "How to get dynamodb to only return certain columns",
},
{
"type": "HASHTAG",
"title": "#dynamodb",
},
]
},
...
]
I am trying to return all posts that have reference of type "HASHTAG" and VALUE "#dynamodb". I have tried this but it always returns null (running in node.js):
const params = {
TableName: "tableName",
ScanIndexForward: false,
FilterExpression: "#references.#type = :referenceValue",
ExpressionAttributeNames: {
"#references": "references",
"#type": "HASHTAG"
},
ExpressionAttributeValues: {
":referenceValue": "#dynamoDB"
}
}
const response = await docClient.scan(params).promise();
console.log(response);
And only returns (successfully) an empty array.
Use the contains function to filter on items in a list. In your case, return posts that have an item like :map at the path indicated by #references.
FilterExpression: 'contains(#references, :map)',
ExpressionAttributeNames: { '#references': 'references' },
ExpressionAttributeValues: {
':map': {
type: 'HASHTAG',
title: '#dynamodb',
},
},
I am trying to get a result from my dynamodb database and ran into a problem, I have this data in my orders table.
{
"orders": [
{
"id": "24950-05675",
"orderNumber": null,
"orderProduct": [
{
"id": "28",
"relatedProductsID": null,
"quantity": 1
},
{
"id": "31",
"relatedProductsID": null,
"quantity": 2
},
{
"id": "99",
"relatedProductsID": null,
"quantity": 3
}
]
}
]
}
and I trying to query for the values inside orderProduct attribute as you can see is a list of objects, so am using FilterExpression with contains in my query like this.
productId = {id: '28'}
let attributes = {
country: { String: ':country', Name: 'country', Value: country },
orderProduct: { String: ':orderProduct', Name: 'orderProduct', Value: productId }
};
const { query } = this.generateQueryFull(attributes);
let params = this._createParamObject({
IndexName: 'countryIndex',
KeyConditionExpression: query.string,
ConditionExpression: 'enabled = true',
ExpressionAttributeNames: query.atributeNames,
ExpressionAttributeValues: query.atributeValues,
FilterExpression: 'contains(#orderProduct, :orderProduct)'
});
and running with query like this:
let response = await this.dbService.client
.query(params)
.promise();
The query is generating without problems and the consult is executing correctly.
So the idea is to filter in the list orderProduct by the propertie { id: <string>}, I have done this before without problem with object lists, but when I try this implementation I don't get results but also don't get any error.
I do not know what I can be doing wrong if someone has an idea it would be very helpful.
the final query
query string
{"string":"#country = :country","atributeNames":"#country":"country","#orderProduct":"orderProduct"},"atributeValues":{":country":"co",":orderProduct":{"id":"31"}}}
How can I getthe data that has email as abc#gmail.com in mongoDB?I don't know the Key Name and I want to iterate through all the data.
I have data like this:
{
"_id":"5c0a1589a5a41b2ae707317b",
"test1":{
"email":"abc#gmail.com",
"phoneNo":"123456897",
"endpointId":"test1"
}
}
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email":"abc#gmail.com",
"phoneNo":"123456897",
"endpointId":"test2"
}
}
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email":"pqr#gmail.com",
"phoneNo":"123456897",
"endpointId":"test3"
}
}
But the object key is not known at the time of searching. I want to iterate through all the data and get matched data that has specific email.
If I know the key name like test1,test2 etc then I can use find({test1:{...}}) but Here I don't know the key value.
So, how can I do that?
You can use below aggregation using $objectToArray in mongodb 3.4 and above
db.collection.aggregate([
{ "$addFields": {
"field": { "$objectToArray": "$$ROOT" }
}},
{ "$match": { "field.v.email": "abc#gmail.com" }},
{ "$project": { "field": 0 }}
])
I am assuming you get the objects in array type.
I made a method named findObject. This method will take the object array and the desired email.
Finally, return the first object, that matched with the email.
const data = [{
"_id":"5c0a1589a5a41b2ae707317b",
"test1":{
"email": "abc#gmail.com",
"phoneNo": "123456897",
"endpointId":"test1"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email": "abc#gmail.com",
"phoneNo": "123456897",
"endpointId":"test2"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"test2":{
"email": "pqr#gmail.com",
"phoneNo": "123456897",
"endpointId": "test3"
}
}];
const findObject = (data, email) => {
for (let index=0; index<data.length; index++) {
const currentData = data[index];
for (let property in currentData) {
if (property != '_id' && currentData[property].email == email) {
return currentData;
}
}
}
return null;
}
let desiredObject;
const desiredEmail = 'abc#gmail.com';
desiredObject = findObject(data, desiredEmail);
console.log(desiredObject);
And the output will be
{ _id: '5c0a1589a5a41b2ae707317b',
test1:
{ email: 'abc#gmail.com',
phoneNo: '123456897',
endpointId: 'test1' } }
I think you can't do query on totally unknown field! if you could change your schema see here for more info, also you could write script to migrate to a new DB with new schema:
// new doc instance
{
"_id":"5c0a1589a5a41b2ae707317b",
"obj": {
"name": "test1"
"email":"abc#gmail.com"
"phoneNo":"123456897",
"endpointId":"test1"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"obj": {
"name": "test2"
"email":"abc#gmail.com"
"phoneNo":"123456897",
"endpointId":"test2"
}
},
{
"_id":"5c0a1989a5a41b2ae807317b",
"obj": {
"name": "test3"
"email":"pqr#gmail.com"
"phoneNo":"123456897",
"endpointId":"test3"
}
}
otherwise, check this may works correctly. if all of them is not effective so make a query to get all of your data as an Array and use filter method on it:
Model.find({}, (err, docs) => {
const result = docs.filter((doc) => {
for (key in doc) {
if (doc[key].email === 'abc#gmail.com')
return doc;
}
});
console.log(result);
});
I currently have a List attribute in my dynamodb table:
name: "Test User"
recommendations: []
I would like to add new item to the recommendations attribute using the UpdateExpression
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid, // WHERE uuid is event.uuid
},
UpdateExpression: "SET #recommendations = :recommendation",
ExpressionAttributeNames: {
"#recommendations": "recommendations",
},
ExpressionAttributeValues: {
":recommendation": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation
}]
},
ReturnValues:"UPDATE_NEW"
};
dynamodb.update(params, function(err, data) { }
I managed to add an object map to recommendations list but when I want to add another one it will replace the object in the recommendation list.
I also tried to use the ADD in UpdateExpression
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid,
},
UpdateExpression: "ADD #recommendations :recommendation",
ExpressionAttributeNames: {
"#recommendations": "recommendations",
},
ExpressionAttributeValues: {
":recommendation": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation,
}]
},
ReturnValues:"ALL_NEW"
};
dynamodb.update(params, function(err, data) { }
but Im getting an error
"Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST",
Okay I already figured out how to add an object to existing map attribute of an item. I used list_append
this will add an object to existing map attribute
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid,
},
UpdateExpression: "SET #attrName = list_append(#attrName, :attrValue)",
ExpressionAttributeNames: {
"#attrName": "recommendations",
},
ExpressionAttributeValues: {
":attrValue": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation
}]
},
ReturnValues:"ALL_NEW"
};
i need to update a list on my aws-dynamo database. i have created a table with partition key : email. then iam insert some email id to the table successfully. Now my table like this
email
manaf1#gmail.com
manaf2#gmail.com
manaf3#gmail.com
Then, i tried to update the table with new key "details" and its value is a list. this is my code
var AWS = require("aws-sdk");
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput":{ "id": "1","mob": "978956" }
}
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.update(params, function (err, data) {
if (err)
console.log(JSON.stringify(err, null, 2));
else
console.log(JSON.stringify(data, null, 2));
});
But i got error like this
{
"message": "Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: list_append, operand type: M",
"code": "ValidationException",
"time": "2016-10-26T11:04:60.756",
"requestId": "SN0NPRHDFHUKBBJHOVI0DFHHRQNSO5AEMVJFFGHF9ASFHUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 0
}
i need response like this after updation
column1 : email
column2 : details
manaf1#gmail.com |
[{"id":"1","mob":"978956"},{"id":"2","mob":"767886"}]
manaf2#gmail.com |
what is the issue related with my code?
As AWS documentation for list_append says:
The new element must be contained in a list, for example to add 2 to a
list, the operand would be [2]
So you need to append an array of objects, not just an object:
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }]
}
};
If the property does not exist in the object, you can use if_not_exists operand:
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set if_not_exists(#details, []) set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }]
}
};
Use list_append() and if_not_exists() together to append to a potentially non-existent list column:
var params = {
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append(if_not_exists(#details, :empty_list), :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }],
":empty_list": []
}
};
When the details attribute is NOT present in the item, the update expression should have just SET without the list_append.
UpdateExpression : "SET #details = :details"
When the details attribute is present in the item and the new update needs to add additional elements in the list, then list_append can be used to add the new element to the list.
UpdateExpression : "set #details = list_append (#details, :details)"