aws / aws/aws-sdk-java-v2

Add support for attribute deletion in `DynamoDbTable.updateItem` when using `IgnoreNullsMode.SCALAR_ONLY`

Aperta
#6,468 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
feature-request needs-triage
Lingua principale
Java
Stelle
2.6k
Fork
1k
Merge medio
2g 9h
PR unite (30g)
51

Descrizione

### 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

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Inizia dal punto di ingresso del client avanzato DynamoDbTable.updateItem e dalla relativa gestione di IgnoreNullsMode, confrontando SCALAR_ONLY con DEFAULT; l’issue identifica inoltre DynamoDbClient come alternativa di basso livello. Il lavoro è completato quando Optional.empty() elimina l’attributo corrispondente negli aggiornamenti parziali e completi, mentre null mantiene il comportamento documentato.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
java
Ambito
databases
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.