Azure Cosmos Spring Partial Update Document Id and _etag

Murillo, Antonio J 20 Reputation points
2024-08-26T19:34:28.7633333+00:00

I’m working with the patch feature with Spring Data Cosmos (Java Spring Boot). I have a scenario where I need to patch a field in a deeply nested object within my main document class, User.

Suppose that I need to update a flag within User at the path myParentField.flagImPatching. However, the application I'm working on does not have access to the full User document or model; it only has access to the MyParent class (the type of the myParentField field within User). Here’s an outline of the models:

public class User {
	@Id
    private String userId;

	@Version
	private String _etag;

    private int count;

    @PartitionKey
	private String somePartitionKeyValue;

	private MyParent myParentField;

    private SomeOtherParent otherParent;

    private AnotherParent anotherParent;

    // has other fields too...
}


public class MyParent {
	private boolean flagImPatching;
}

In my patch operation, I’d like to update flagImPatching within MyParent using the CosmosPatchOperations functionality.

Questions:

  1. Can I pass PartialUser.class to Repository.save() like this instead of User.class (and instead of a UserRepository) when applying the patch operation? Given that myParentField is a child-object within User, would this still correctly update the User document in Cosmos DB? Even if my repository only knows about PartialUser?
  2. Regarding the patch operation: The User model includes an @Id for the document ID and a @Version annotated field for the _etag (for optimistic concurrency). Do I need to supply these fields when performing the patch operation with CosmosPatchOperations, even if I’m only updating a specific nested field? I've shown that below.

Here’s how I’m considering the operation, even though I don’t have access to the full User object (taken from an example here: https://github.com/Azure/azure-sdk-for-java/pull/32630):

@Repository
public interface PartialUserRepository extends CosmosRepository<PartialUser, String> { }


...


public class PartialUser {
	@Id
	private String userId;

	@Version
	private String _etag;

	private MyParent myParentField; 
}


...


CosmosPatchOperations patchOperations = CosmosPatchOperations
	.create()
	.replace("/myParentField/flagImPatching", true);

// Assuming I have the necessary identifiers (userId and partition key)
// but I only have access to MyParent class, not the full User (so I've just stuck it inside a container PartialUser)
PartialUser patchedPartialUser = partialUserRepository.save(userId, new PartitionKey(partitionKeyValue), PartialUser.class, patchOperations);
Azure Cosmos DB
Azure Cosmos DB
An Azure NoSQL database service for app development.
1,612 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Amira Bedhiafi 23,096 Reputation points
    2024-08-27T21:11:34.7266667+00:00

    Q1 : Yes, you can pass PartialUser.class to the Repository.save() method. However, it's essential to understand that the PartialUser class you are creating is a partial representation of the User document in Cosmos DB. When you pass PartialUser.class, you are instructing the repository to treat this class as a projection of the User document, meaning that it only contains a subset of fields present in the User document.

    In your scenario, if you only want to update myParentField.flagImPatching, your approach to use PartialUser.class should work correctly as long as the Cosmos DB patch operation is correctly formed. The Cosmos DB SDK is designed to work with partial document updates and will only modify the fields you specify.

    Q2: Yes, you do need to supply the @Id (document ID) and @Version (etag) fields when performing the patch operation. Here’s why:

    Document ID (@Id): The document ID is necessary to locate the specific document within the collection that you want to update.

    Etag (@Version): The etag is used for optimistic concurrency control. Cosmos DB uses the etag to ensure that no other update has been made to the document between the time it was retrieved and the time the patch operation is applied. If the etag in the request does not match the current etag of the document in the database, the patch operation will fail to prevent conflicts.

    Given your scenario, the patch operation would look something like this:

    javaCopy code
    CosmosPatchOperations
    

    In this operation, you are essentially telling Cosmos DB to replace the value at /myParentField/flagImPatching with true. The PartialUser object contains the required fields (userId, _etag) to ensure that this operation is performed on the correct document and that the update is safe in terms of concurrency.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.