58

I am using a JSON structure to store details of a person. Basically name, phone, registeredTimestamp etc., will be other attributes, and Primary key will be the email address.

markedLocations, visitedLocations, searchHistory and recommendation are the lists or Map as AWS calls it. It will contain many JSON objects.

JSON Structure-

{
    "name":"Mama Miya",
    "phone":"9383883223",
    "registeredTimestamp":"some-time",
    "lastActiveTimestamp":"some-time",
    "signinType":"facebook",
    "additionalSigninData":{
        "key1":"value1",
        "key2":"value2"
    },
    "markedLocations":[
        {
            "latitude":"77.33",
            "longitude":"12.33",
            "name":"Home",
            "description":"my new home",
            "placeid":"55334433",
            "image":"url/abc.png"
        }
    ]
}

From the app, if the user visits a new location, I need to add a new JSON Object to the markedLocations. So the markedLocations should look something like-

"markedLocations":[
    {
        "latitude":"77.33",
        "longitude":"12.33",
        "name":"Home",
        "description":"my new home",
        "placeid":"55334433",
        "image":"url/abc.png"
    },{
        "latitude":"22.11",
        "longitude":"22.55",
        "name":"Ocean",
        "description":"Ocean",
        "placeid":"32423423",
        "image":"url/icean.png"
    }
]

Code/Schema-

var item = {
        'email': {'S': req.body.email},
        'phone': {'S': req.body.phone},
        'registeredTimestamp': {'S': req.body.registeredTimestamp},
        'lastActiveTimestamp': {'S': req.body.lastActiveTimestamp},
        'signinType': {'S': req.body.signinType},
        'version': {'S': req.body.version},
        'markedLocations': {'L': req.body.markedLocations}
    };

I checked -

  • In DynamoDB how do I append an element to a list field using Java link

  • updating a JSON array in AWS dynamoDB link

  • Updating a Set in Dynamo db using Node Js link

  • how to update item in dynamoDB using nodejs? link

  • And checked AWS docs for UpdateItem API. I didn't find anything relevant to my problem/doubt.

Please can you tell me if there is a way to append the JSON array with a new JSON object in NodeJS? I am not able proceed on how to implement the same.

OR

Should I create separate table for each Array and have email as primary key and timestamp as sort key and proceed?

PS: I am new to DynamoDB, I've worked with MongoDB earlier and there are ways to work with JSON arrays and objects there. Unable to find a way here.

Community
  • 1
  • 1
bozzmob
  • 12,364
  • 16
  • 50
  • 73
  • 1
    Do you know how to do it in Javascript? That's how you would do it. Node.JS uses Javascript. – Robert Harvey Dec 30 '16 at 18:10
  • @RobertHarvey No. I don't know how to solve THIS problem in JS. The whole of AWS Documentation have examples and API demos using Java, PHP and .Net. I am not sure of what API to use or how to construct the code. The StackOverflow Questions I have listed either don't have answers at all or are mostly to replace the existing value. I need to append to the existing array. – bozzmob Dec 30 '16 at 18:24
  • 1
    It sounds like you're trying to find an API or library somewhere for a simple operation that should be easily done in Javascript. Have a look at [this post](http://stackoverflow.com/questions/4538269), especially [this answer](http://stackoverflow.com/a/4538314/102937). You don't need NodeJS, Dynamo or anything else to accomplish this. Note that the author of that post made the same mistake you did; *you don't need jQuery to do this either.* – Robert Harvey Dec 30 '16 at 18:29
  • @RobertHarvey Thanks for correcting me. But, again, back to the question, say if I have 2 objects in an array(object literal as mentioned) already in DynamoDB, how do I append another Object to it? How can I perform `splice` or `push` operation on the DB? It's not possible right? – bozzmob Dec 30 '16 at 19:03
  • @RobertHarvey Updated my question with the schema structure. – bozzmob Dec 30 '16 at 19:05

1 Answers1

111

Use list_append() and if_not_exists() together in an UpdateExpression to append to a potentially non-existent list column:

var AWS = require('aws-sdk')
var DB = new AWS.DynamoDB.DocumentClient()

function appendMarkedLocation (personId, location) {
  return DB.update({
    TableName: 'people',
    Key: { id: personId },
    ReturnValues: 'ALL_NEW',
    UpdateExpression: 'set #markedLocations = list_append(if_not_exists(#markedLocations, :empty_list), :location)',
    ExpressionAttributeNames: {
      '#markedLocations': 'markedLocations'
    },
    ExpressionAttributeValues: {
      ':location': [location],
      ':empty_list': []
    }
  }).promise()
}

appendMarkedLocation('somePeronId', {
  latitude: '22.11',
  longitude: '22.55',
  name: 'Ocean',
  description: 'Ocean',
  placeid: '32423423',
  image: 'url/icean.png'
}).then(console.log)
idbehold
  • 16,833
  • 5
  • 47
  • 74
  • 2
    This is exactly something I was looking for. Will test it and update. Thanks a lot. – bozzmob Dec 30 '16 at 20:55
  • Please can you tell me what Attribute type should I be using for each object in the array? Should it be a List? – bozzmob Jan 07 '17 at 14:36
  • 4
    @bozzmob if you're using the DocumentClient like I am in my answer then you shouldn't need to care about the DyanmoDB internal types at all. The DocumentClient would cast each item in the `markedLocations` List to a Map type internally. So `markedLocations` would end up being a List of Maps. – idbehold Jan 07 '17 at 17:16
  • I didn't realize the object to append had to be wrapped in an array. It seems more like an array merge than an append. – Phil D. Nov 13 '20 at 09:04
  • 1
    @PhilD. a merge implies that values in the "target" array could be replaced/overwritten. That is not the case here. I agree a better term might have been `list_concat`. But in either case the fact that this function takes an array as input make it is more flexible than one which only took a single item to append. That way if you had more than one item to append you can do it in a single call instead of multiple. – idbehold Nov 18 '20 at 15:07