Add support for attribute deletion in `DynamoDbTable.updateItem` when using `IgnoreNullsMode.SCALAR_ONLY`
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 51
Description
### Describe the feature
The `DynamoDbTable.updateItem` method provides two modes for handling `null` values via the `IgnoreNullsMode` setting:
- `IgnoreNullsMode.DEFAULT`: Attributes with `null` values are removed, resulting in a full item update (the entire item must be specified).
- `IgnoreNullsMode.SCALAR_ONLY`: Attributes with `null` values are ignored, allowing a partial update where only the provided attributes are written.
While partial updates are efficient and convenient, since they only write the modified fields, they currently do not support attribute deletion. The only way to delete an attribute is by using `IgnoreNullsMode.DEFAULT`, which forces a full item overwrite and requires all existing attributes to be specified, even when only a few need updating. In practice, this means the existing item must first be retrieved from DynamoDB before performing the update, so that all current attributes can be included in the overwrite request.
This limitation becomes especially problematic for items with a large number of attributes, where a full update incurs unnecessary read and write overhead, adds latency, and increases code complexity.
### Use Case
Consider a `BigItem` entity with a large number of attributes (e.g., 50 fields such as `attr1`, `attr2`, …, `attr50`):
```java
@Getter
@Builder(toBuilder = true)
@DynamoDbImmutable(builder = BigItem.BigItemBuilder.class)
public class BigItem {
@Getter(onMethod_ = @DynamoDbPartitionKey)
private final String id;
private final String attr1;
private final String attr2;
private final String attr3;
// More attributes to make the item "big"
private final String attr50;
}
```
Suppose we need to remove `attr3`.
With the current API, this requires first retrieving the existing item from DynamoDB, and then performing a full item update using `IgnoreNullsMode.DEFAULT`, meaning all other attributes must be re-specified, even if they have not changed:
```java
BigItem bigItem = dynamoDbTable.getItem(
b -> b.key(k -> k.partitionValue(id).build()));
BigItem fullUpdate = bigItem.toBuilder()
.attr3(null)
.build();
dynamoDbTable.updateItem(
b -> {
b.item(fullUpdate);
b.ignoreNullsMode(IgnoreNullsMode.DEFAULT);
}
);
```
While it is technically possible to remove a single attribute using a low-level `UpdateItemRequest` with `DynamoDbClient`, constructing the appropriate update expression becomes cumbersome, especially in more complex scenarios where both attribute updates and deletions must occur together.
### Proposed Solution
Introduce support for fields of type `Optional` within the enhanced client data model.
When performing a partial update with `IgnoreNullsMode.SCALAR_ONLY`:
- Attributes with `null` values would continue to be ignored (unchanged behavior).
- Attributes with `Optional.empty()` would be removed from the item.
In the case of a full update, both `null` and `Optional.empty()` should indicate that the corresponding attribute must be deleted.
This approach enables developers to explicitly mark attributes for deletion without requiring a full item overwrite, while maintaining backward compatibility with existing behavior.
Example:
```java
@Getter
@Builder(toBuilder = true)
@DynamoDbImmutable(builder = BigItem.BigItemBuilder.class)
public class BigItem {
@Getter(onMethod_ = @DynamoDbPartitionKey)
private final String id;
private final String attr1;
private final Optional attr2;
private final Optional attr3;
// More attributes to make the item "big"
private final String attr50;
}
```
In this example, we assume that `attr2` and `attr3` are nullable fields represented as `Optional`. If we want to delete `attr3`, we can explicitly set it to `Optional.empty()` in a partial update:
```java
BigItem partialUpdate = BigItem.builder()
.id(id)
.attr3(Optional.empty())
.build();
dynamoDbTable.updateItem(
b -> {
b.item(partialUpdate);
b.ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY);
}
);
````
This approach allows clear intent for attribute deletion within partial updates, without needing to retrieve or rewrite the full item.
### Other Information
_No response_
### Acknowledgements
- [x] I may be able to implement this feature request
- [ ] This feature might incur a breaking change
### AWS Java SDK version used
2.33.1
### JDK version used
21.0.3
### Operating System and version
Ubuntu 24.04
Contributor guide
Assessment
This issue has not been assessed yet.