update List of maps in Dynamodb - node.js

Below is my DynamoDB structure:
{
id : "Sample_id",
details: {
wf: [{
wid: "12345",
wname: "name_1"
}]
}
}
Now I want add a new map object to "wf", I have tried both ADD and SET with update but both replacing the existing object with the new one.
Below is the code i tried
var params = {
TableName: p_table,
Key: {
"id" : "Sample_id"
},
UpdateExpression: "SET details.wf = list_append(details.wf, :vals)",
ExpressionAttributeValues: {
":vals" : [{'wid': "98765", 'wname': 'name_2'}]
}
};
ddb.update(params, function(err, data) {
if(err)
console.log(err);
else
console.log(data)
});
Current output with the above code:
{
id : "Sample_id",
details: {
wf: [{
wid: "98765",
wname: "name_2"
}]
}
}
Expected Output:
{
id : "Sample_id",
details: {
wf: [{
wid: "12345",
wname: "name_1"
},
{
wid: "98765",
wname: "name_2"
}]
}
}
How can I achieve the expected out

Updated my param object to below and it worked for me
Added an index 99999 (some big random index beyond which I do not expect my list to grow), in-spite of index 99999 while appending the data in lambda to the existing list it sits with next available index
var params = {
TableName: p_table,
Key: {
"id" : "Sample_id"
},
UpdateExpression: "SET details.wf[999999] = :vals",
ExpressionAttributeValues: {
":vals" : {'wid': "98765", 'wname': 'name_2'}
}
};
ddb.update(params, function(err, data) {
if(err)
console.log(err);
else
console.log(data)
});

Related

how to update an object of an element in array in mongodb?

This is the structure i have, i want to update the nested array element if an object key matches for example - i want to match grnno :"10431000" and update the other keys of that object like vehicle_no,invoice_no etc.
{
"_id" : ObjectId("5f128b8aeb27bb63057e3887"),
"requirements" : [
{
"grns" : [
{
"invoice_no" : "123",
"vehicle_no" : "345",
"req_id" : "5f128c6deb27bb63057e388a",
"grnno" : "10431000"
},
{
"invoice_no" : "abc",
"vehicle_no" : "def",
"req_id" : "5f128c6deb27bb63057e388a",
"grnno" : "10431001"
}
]
}
]
}
I have tried this code
db.po_grn.update({
"requirements.grns.grnno":"10431001"
}, {
$set: {
"requirements.$.grns": {"invoice_no":"test",vehicle_no:"5455"}
}
})
But this is changing the structure i have like this
"requirements" : [
{
"grns" : {
"invoice_no" : "test",
"vehicle_no":"5455"
},
"req_id" : ObjectId("5f128b8aeb27bb63057e3886")
}
],
grns key should be array, and update should be of the particular object which matches the key "grnno". Please help me out. Thanks.
==Edit==
var grnno = req.body.grnno;
db.po_grn.find({
"requirements.grns.grnno":grnno
}).toArray(function(err, po_grn) {
console.log("po_grn",po_grn);
if (po_grn.length > 0) {
console.log("data.grn.grnno ", grnno);
var query = {
requirements: {
$elemMatch: {
"grns.grnno": grnno
}
}
};
var update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': data.invoice_no,
'requirements.$[].grns.$[inner].vehicle_no': data.vehicle_no,
}
};
var options = {
arrayFilters: [
{ "inner.grnno" : grnno }
]
};
db.po_grn.update(query, update, options
, function(er, grn) {
console.log("grn",grn,"er",er)
res.send({
status: 1,
message: "Grn updated successfully"
});
}
);
} else {
res.send({
status: 0,
message: "Grn not found "
});
}
})
Use a combination of $[] positional-all operator with array filters to update your inner nested document.
var query = {
requirements: {
$elemMatch: {
"grns.grnno": "10431001"
}
}
};
var update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': "test",
'requirements.$[].grns.$[inner].vehicle_no': "5455",
}
};
var options = {
arrayFilters: [
{ "inner.grnno" : "10431001" }
]
};
db.collection.update(query, update, options);
Update -
NodeJS native MongoDb driver code attached, which is working fine
const { MongoClient } = require('mongodb');
const url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) {
throw err;
}
const dbo = db.db("test");
(async() => {
const query = {
requirements: {
$elemMatch: {
"grns.grnno": "10431001"
}
}
};
const update = {
$set: {
'requirements.$[].grns.$[inner].invoice_no': "test",
'requirements.$[].grns.$[inner].vehicle_no': "5455",
}
};
const options = {
arrayFilters: [
{ "inner.grnno" : "10431001" }
],
multi: true
};
try {
const updateResult = await dbo.collection("collection").update(query, update, options);
} catch (err) {
console.error(err);
}
db.close();
})();
});

Querying nested object using $find by applying conditions in Mongodb

This is my json object
{
"account_id" : "1",
"sections" : [
"name" : "sec1",
"label" : {
"label1" : "text1",
"label2" : "text2"
}
},
"name" : "sec2",
"label" : {
"label3" : "text3",
"label4" : "text4",
"label5" : "text5"
}
},
]
}
So in this json I wanted to query the label object where sector= sec1. I have used the below code but it didn't work.
var getData = (db, query) => {
return db
.collection(TABLE_NAME)
.find(query, { account_id: { sections: { label: 1 } } })
.toArrayAsync();
};
var dataList = (db, event) => {
let dataQuery = {
account_id: id,
'sections.name': event.params.section
};
return getData(db, dataQuery);
};
module.exports.getData = (event, cb) => {
return using(connectDatabase(), db => {
return dataList (db, event);
}).then(data => cb(null, responseObj(data, 200)), err =>
cb(responseObj(err, 500)));
};
Could someone kindly help me? Thanks inadvance.
Try something like this. use $project, we can selectively remove or retain field and we can reassign existing field values and derive entirely new values. after projecting the labels and name do a $match to extract the document by name. One thing to notice is that by using $project,it will automatically assign the document's _id.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: { account_id: your_id }
},
{
$unwind: '$sections'
},
{
$project:{labels:'$sections.label',name:'$sections.name'}
},
{
$match:{name:section_name}
}]).toArray();
};
You have to use aggregate method with $unwind syntax to find item in array of object.
var dataList = (db, event) => {
return db
.collection(TABLE_NAME)
.aggregate([
{
$match: {
account_id: id,
}
},
{ $unwind: "$comments" },
{
$match: {
'name': event.params.section
}
}
])
.toArrayAsync();
};
Result:
[{
"account_id": "1",
"sections": {
"name": "sec2",
"label": {
"label3": "text3",
"label4": "text4",
"label5": "text5"
}
}
}]

How do I update nested list data in dynamodb using document client

I have a dynamoDB table that has an Item that includes a UserId and a List of lists. It looks like this:
Item:
{
UserId: 'abc123',
Lists: [
{
id: 1,
title: 'My favorite movies',
topMovies: [
{
id: 1,
title: 'Caddyshack'
},
{
id: 2,
title: 'Star Wars'
}
]
}
]
}
Now, lets the user has created a new list titled, "My favorite TV Shows", and wants to insert it into the Lists array with id: 2.
How would I update this object using document client. I've looked through several examples and I've found nothing that explains what I'm trying to do. It's making me think that perhaps I'm not using DynamoDB correctly and I should have a different object schema.
I've attempted using this, but it is overwriting my previous object.
exports.handler = (event, context, callback) => {
console.log(event);
const params = {
TableName: "top-ten",
Key: {
"UserId": 'abc123',
},
UpdateExpression: "set Lists =:newItem",
ExpressionAttributeValues: {
":newItem": {
"id": 2,
"title": "Favorite TV Shows",
"topMovies": [{"id": 1, "title" : "The Simpsons"}]
},
},
ReturnValues: "UPDATED_NEW"
};
dynamodb.update(params, function(err, data) {
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
callback(null, data);
}
});
};
EDIT: Ok, I've figured out that if I put
UpdateExpression: "set Lists[1] =:newItem"
it updates the item correctly. But now, how do I know how many items I have in my list array?
You should use list_append. The function adds two lists together, so you need to make your item to add a list.
exports.handler = (event, context, callback) => {
console.log(event);
const params = {
TableName: "top-ten",
Key: {
"UserId": 'abc123',
},
UpdateExpression : "SET #attrName = list_append(#attrName, :attrValue)",
ExpressionAttributeNames : {
"#attrName" : "Lists"
},
ExpressionAttributeValues : {
":attrValue" : [{
"id": 2,
"title": "Favorite TV Shows",
"topMovies": [{"id": 1, "title" : "The Simpsons"}]
}]
},
ReturnValues: "UPDATED_NEW"
};
dynamodb.update(params, function(err, data) {
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
callback(null, data);
}
});

The number of conditions on the keys is invalid dynamo db with node js

docClient.update({
TableName: 'patient',
Key: {
"patientId": "TIGERPAT0001"
},
UpdateExpression: "set title = :x, name = :y",
ExpressionAttributeNames: {
"#name": "name"
},
ExpressionAttributeValues: {
":x": 'title value abc',
":y": 'name value xyz'
}
}, function (err, data) {
if (err) {
json.status = '0';
json.result = { 'error': 'Unable to Edit Patient : ' + JSON.stringify(err) };
res.send(json);
} else {
json.status = '1';
json.result = { 'sucess': 'Patient Edited Successfully :' };
res.send(json);
}
});
when use above code, i got res :
Unable to Edit Patient Error : `{"message":"The number of conditions on the keys is invalid",
"code":"ValidationException",
"time":"2017-09-13T07:12:56.608Z",
"requestId":"a01c707c-86b4-41a5-a1c5-92b9ea07c026",
"statusCode":400,"retryable":false,
"retryDelay":6.368631970657979}`
What do I miss / any mistake??
I think you have used multiple keys while creating table.
If you have used n number of keys while creating table, then here also you need to pass n number of keys.
Note below, we are passing in id1 and id2 keys as well.
Ex:
docClient.update({
TableName: 'patient',
Key: {
"patientId": "TIGERPAT0001",
"id1": "id1value",
"id2": "id2value"
},
UpdateExpression: "set title = :x, #name = :y",
ExpressionAttributeNames: {
"#name": "name"
},
ExpressionAttributeValues: {
":x": 'title value abc',
":y": 'name value xyz'
}
}, function (err, data) {
if (err) {
json.status = '0';
json.result = { 'error': 'Unable to Edit Patient : ' + JSON.stringify(err) };
res.send(json);
} else {
json.status = '1';
json.result = { 'sucess': 'Patient Edited Successfully :' };
res.send(json);
}
});
Please replace id1 and id2 with your keys

node.js passing a parameter to DynamoDB updateItem method

I want to write a function that updates given parameter in dynamodb.
For example in a dynamodb table where each userId is the key I have values like
{
"categoryname": "a",
"skillState": "a",
"skipcount": 1,
"userId": "amzn1.ask.account.xxx”
}
I wanna set the "categoryname": "b" although there might be 10-15 fields like this so I dont wanna hard code the field name.
function (userId,itemToUpdate,itemValue,callback) {
var updateExpressionString = "SET #"+itemToUpdate+" =:val1";
var expressionAtt = '#'+itemToUpdate + '';
console.log(updateExpressionString)
console.log(expressionAtt)
this.dynamodb.updateItem({
TableName: constants.dynamoDBDetailTableName,
Key: {
userId: {
S: userId
}
},
UpdateExpression: updateExpressionString,
ExpressionAttributeNames : {
expressionAtt : itemToUpdate
},
ExpressionAttributeValues : {
':val1': {'S':itemValue}
}
}, function (err, data) {
if (err) {
console.log(err)
console.log('Error ')
} else if (data.Item === undefined) {
}else {
console.log(data)
}
});
}
In ExpressionAttributeNames:
{ ValidationException: ExpressionAttributeNames contains invalid key: Syntax error; key: "expressionAtt"
This throws error obviously thinking that expressionAtt is the key while it is a local variable.
I am new to node.js , how can pass the local variable in to ExpressionAttributeNames and ExpressionAttributeValues
One way of dealing with this could be to pull the object out of updateItem, put it into its own variable like so:
var item = {
TableName: constants.dynamoDBDetailTableName,
Key: {
userId: {
S: userId
}
},
UpdateExpression: updateExpressionString,
ExpressionAttributeNames: {},
ExpressionAttributeValue: {
':val1': {'S': itemValue}
}
};
item.ExpressionAttributeNames[expressionAtt] = itemToUpdate;
this.dynamodb.updateItem(item);
I believe that will fix your problem

Resources