"After all, the engineers only needed to refuse to fix anything, and modern industry would grind to a halt." -Michael Lewis
Nov 2020
Nested attributes in DynamoDB are a way to group data within an item together. The attributes are said to be nested if they are embedded within another attribute.
Building off a previous post where we set up an embedded DynamoDB instance in a java test suite, I'll provide here some examples for working with nested attributes.
The source code that follows can be seen on Github.
First let's create a table and insert some data:
@Test
public void nestedAttributes() throws Exception {
String currentTableName = "NestedAttributesTest";
createTableAndWaitForComplete(currentTableName);
Map<String, AttributeValue> attributes = Map.of(
COMPANY, AttributeValue.builder().s("Motorola").build(),
MODEL, AttributeValue.builder().s("G1").build(),
"MetadataList", AttributeValue.builder().l(
AttributeValue.builder().s("Super Cool").build(),
AttributeValue.builder().n("100").build()).build(),
"MetadataStringSet", AttributeValue.builder().ss("one", "two", "three").build(),
"MetadataNumberSet", AttributeValue.builder()
.bs(SdkBytes.fromByteArray(new byte[] {43, 123}), SdkBytes.fromByteArray(new byte[] {78, 100}))
.build()
);
PutItemRequest populateDataItemRequest = PutItemRequest.builder()
.tableName(currentTableName)
.item(attributes)
.build();
StepVerifier.create(Mono.fromFuture(dynamoDbAsyncClient.putItem(populateDataItemRequest)))
.expectNextCount(1)
.verifyComplete();
Given the primary key as a composite partition and sort key, where here it is "Motorola" as the partition and "G1" as the sort, there are three nested attribute types in play:
Note that we omitted one set type of the three that are available, which is the number set.
We can now get this item out of dynamo, and the access patterns should be familiar to us at this point:
GetItemRequest getItemRequest = GetItemRequest.builder()
.tableName(currentTableName)
.key(getMapWith("Motorola", "G1"))
.build();
StepVerifier.create(Mono.fromFuture(dynamoDbAsyncClient.getItem(getItemRequest)))
.expectNextMatches(getItemResponse -> {
List<AttributeValue> listOfMetadata = getItemResponse.item().get("MetadataList").l();
List<String> stringSetMetadata = getItemResponse.item().get("MetadataStringSet").ss();
return listOfMetadata.size() == 2
&& listOfMetadata.stream().anyMatch(attributeValue -> "Super Cool".equals(attributeValue.s()))
&& listOfMetadata.stream().anyMatch(attributeValue -> "100".equals(attributeValue.n()))
&& stringSetMetadata.contains("one")
&& stringSetMetadata.contains("two");
}).verifyComplete();
}
Here, we get both the list of attributes and the string set from our item, then making assertions that they all are there and correct.
Remember to check out the source code for this post on Github.
Nick Fisher is a software engineer in the Pacific Northwest. He focuses on building highly scalable and maintainable backend systems.