DynamoDB: How can I create a table with nested JSO

2020-08-12 23:53发布

问题:

I want to create a table in dynamoDB with below structure.

{
  "CartId": 123,
  "UserId": 356,
  "CartItems": [
    {
      "ProductId": 100,
      "Quantity": 50
    },
    {
      "ProductId": 121,
      "Quantity": 51
    }
  ]
}

Everywhere in tutorials and documents it says that we can only have below type of attributes in the table:

  1. Set of Strings

  2. Set of Numbers

  3. Set of Binary

I can't think of a way to store above structure in DynamoDB. Could you please help out?

I am using object mapper Api of java. It would be great if you can also tell me how can I create a class which can be mapped to this particular table structure.

回答1:

Simplest way is use @DynamoDBDocument

  1. Add Maven dependency
<dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-dynamodb</artifactId>
        <version>1.11.186</version>
</dependency>
  1. Create POJO
@DynamoDBTable(tableName = "Customer")
public class Customer
{ 
    @DynamoDBHashKey
    @DynamoDBAutoGeneratedKey
    private String id;

    private String firstName;

    private List<Foo> fooList;
}

@DynamoDBDocument
public static class Foo {
    private String name;
}
  1. Create a repository
@EnableScan
public interface CustomerRepository extends CrudRepository<Customer,String>

Then call customerRepository.save(customer). The result will be like this:

{
  "firstName": "Test",
  "fooList": [
    {
      "name": "foo"
    },
    {
      "name": "foo2"
    }
  ],
  "id": "e57dd681-8608-4712-a39a-f3e0f31a5e27"
}


回答2:

Posting to an old question because I did not think the solution was easy to find. Hope this helps someone.

Step 1: Create a complex Java object that mirrors the structure desired.

List<HashMap<String, Integer>> cartItems = new ArrayList<HashMap<String, Integer>>();
HashMap<String, Integer> item1 = new HashMap<String, Integer>();
item1.put("ProductId", 100);
item1.put("Quantity", 50);
cartItems.add(item1);
HashMap<String, Integer> item2 = new HashMap<String, Integer>();
item2.put("ProductId", 121);
item2.put("Quantity", 51);
cartItems.add(item2);

Step 2: Update DynamoDB item with the complex object.

I use a helper method:

private void updateAttribute(int id, String newAttribute, Object newValue){
    Map<String, Object> newValues = new HashMap<String, Object>();
    newValues.put(":value", newValue);

    UpdateItemSpec updateItemSpec = new UpdateItemSpec()
            .withPrimaryKey("id", id)
            .withUpdateExpression("set " + newAttribute + " = :value")
            .withValueMap(newValues);

    siteTable.updateItem(updateItemSpec);
}

and then call thus:

updateAttribute(123, "CartItems", cartItems);

The newly added cart items attribute displays in DynamoDB like:

{
 "CartItems": [
   {
     "ProductId": 100,
     "Quantity": 50
   },
   {
     "ProductId": 121,
     "Quantity": 51
   }
 ]
}

I have not tested an upsert scenario. In the past, upsert functionality did not seem to be present: https://forums.aws.amazon.com/thread.jspa?threadID=162907

Regarding reads of deeply nested items: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html#DocumentPaths



回答3:

You can store JSONs in Dynamodb as Strings. It all depends on what you want to do with the data and how to retrieve it.

The DynamoDB Java API for instance, introduces Marshaller objects that transforms any Java object into a String so you can store it and fetch it automagically from a DynamoDB attribute.



回答4:

Not sure if these data types were available when this question was asked (there is a good chance that they were not) but these days you'd use the List datatype for the CartItems and each cart item would be of Map datatype.

Reference: DynamoDB Data Types



回答5:

Bit Late to the party but would like to share this. I was able to store a deep nested Json Doc by defining the column attribute as below in my Java Entity.

@DynamoDBAttribute
@DynamoDBTypeConvertedJson
private List<Map<String,Object>> pageData;

Input Json:

 {
    "userId": 359628,
    "platform": "learn-web",
    "inactive_duration": 0,
    "total_time": 15,
    "device_type": "web",
    "page_data": [{
        "page_details": {
            "page_type": "segmentView",
            "time": 15,
            "segment_id": 65590,
            "session_id": 13140,
            "module_id": 4363
        },
        "items": [{
            "type": "component",
            "id": 267307,
            "sub_type": "video",
            "time": 10,
            "metadata": {
                "lastPlaybackRate": 1,
                "currentTime": 0,
                "isLocked": false,
                "video": {
                    "videoType": "BRIGHTCOVE",
                    "viewingTime": 156,
                    "videoSize": 7120441,
                    "url": "5378655747001",
                    "URL": "5378655747001"
                }
            }
        }]
    }]
}

As stored in Dynamo DB-Snap