Java DynamoDB:如何创建具有嵌套 JSON 结构的表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26118067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:52:19  来源:igfitidea点击:

DynamoDB: How can I create a table with nested JSON structure?

javajsonamazon-dynamodb

提问by Amit

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

我想在 dynamoDB 中创建一个具有以下结构的表。

{
  "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

  1. 字符串集

  2. 一组数字

  3. 二进制集

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

我想不出在 DynamoDB 中存储上述结构的方法。你能帮忙吗?

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.

我正在使用 java 的对象映射器 Api。如果您还可以告诉我如何创建一个可以映射到这个特定表结构的类,那就太好了。

采纳答案by kurtzbot

From the JSON structure you gave, I think you are trying to make DynamoDB like a relational database, when really you should be thinking of DynamoDB as a simple flat key-value store. So instead of a table structure like you suggested, I would instead flatten it, and have many rows for each item the customer has in their cart.

根据您提供的 JSON 结构,我认为您正在尝试将 DynamoDB 打造为一个关系型数据库,而实际上您应该将 DynamoDB 视为一个简单的平面键值存储。因此,我不会像您建议的那样使用表格结构,而是将其展平,并为客户的购物车中的每件商品设置多行。

For example

例如

Primary hashkey (UserId) | Hash range key (CartId) | ProductId | Qty
356                        123                       100         50
356                        123                       121         51

In this way, you can get all items in a cart by providing a primary key of 356, with range key 123. This is the DynamoDB way of storing indexable and queryable data. This does mean you are storing two separate rows, however.

通过这种方式,您可以通过提供主键 356 和范围键 123 来获取购物车中的所有商品。这是 DynamoDB 存储可索引和可​​查询数据的方式。但是,这确实意味着您要存储两个单独的行。

A format like this has many advantages, in particular it enables you to create Local Secondary indices on the ProductId to find out how many customers put a particular product into their cart. It should also make it easy to see how the object mapper will work with this table structure.

像这样的格式有很多优点,特别是它使您能够在 ProductId 上创建本地二级索引,以了解有多少客户将特定产品放入他们的购物车。它还应该可以很容易地看到对象映射器将如何处理这个表结构。

回答by Chen Harel

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.

您可以在 Dynamodb 中将 JSON 存储为字符串。这完全取决于您想对数据做什么以及如何检索它。

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.

例如,DynamoDB Java API 引入了 Marshaller 对象,可将任何 Java 对象转换为字符串,以便您可以存储它并从 DynamoDB 属性中自动获取它。

回答by golem

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 CartItemsand each cart item would be of Map datatype.

不确定当问到这个问题时这些数据类型是否可用(它们很有可能不是),但现在您将使用 List 数据类型,CartItems并且每个购物车项目都将是 Map 数据类型。

Reference: DynamoDB Data Types

参考:DynamoDB 数据类型

回答by Laura

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.

步骤 1:创建一个反映所需结构的复杂 Java 对象。

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.

步骤 2:使用复杂对象更新 DynamoDB 项目。

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:

DynamoDB 中新添加的购物车项目属性显示如下:

{
 "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

我还没有测试过 upsert 场景。过去,upsert 功能似乎不存在: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

关于深度嵌套项目的读取:http: //docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html#DocumentPaths

回答by sendon1982

Simplest way is use @DynamoDBDocument

最简单的方法是使用 @DynamoDBDocument

  1. Add Maven dependency
  1. 添加Maven依赖
<dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-dynamodb</artifactId>
        <version>1.11.186</version>
</dependency>
  1. Create POJO
  1. 创建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
  1. 创建存储库
@EnableScan
public interface CustomerRepository extends CrudRepository<Customer,String>

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

然后调用customerRepository.save(customer)。结果将是这样的:

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

回答by Sandeep Lakdawala

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.

晚会有点晚,但想分享这个。通过在我的 Java 实体中定义如下列属性,我能够存储深度嵌套的 Json Doc。

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

Input Json:

输入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

存储在 Dynamo DB-Snap 中