I have been working with Cosmos DB for a while now and until recently, there was one thing which always annoyed me: When updating a JSON document stored in a container, there was no way to only modify a few selected properties of the document.
The entire JSON document had to be fetched by the client first, then locally replace the properties to be updated, and then send the entire document back to Cosmos DB and replace the previous version of the document.
This was always a challenge because first, it added more work for developers and second, there could be concurrency issues if multiple clients could be downloading multiple copies of the document and updating the data and sending back their copy.
But fortunately, now it's possible to partially update a document in Cosmos DB and basically do a PATCH operation while only sending the properties to be changed over the wire.
So in this post, let's have a look at the different ways in which we can partially update documents in Cosmos DB:
Setting up by creating a Cosmos DB document
First, we will create our sample document using code. I should mention I am using v3.30.1 of Azure Cosmos DB .NET core package from nuget: Microsoft.Azure.Cosmos
var endpointUri = "<cosmosdb-endpoint-uri>"; | |
var primaryKey = "<cosmosdb-primary-key>"; | |
var databaseId = "UsersDB"; | |
var containerId = "Users"; | |
var partitionKey = "allusers"; | |
var _cosmosClient = new CosmosClient(endpointUri, primaryKey); | |
var _databaseResponse = await _cosmosClient.CreateDatabaseIfNotExistsAsync(databaseId); | |
var _containerResponse = await _databaseResponse.Database.CreateContainerIfNotExistsAsync(containerId, $"/partitionKey"); | |
var user = new User() | |
{ | |
Id = userIdForDemo, | |
Name = "Vardhaman", | |
Department = "Product", | |
Projects = new Project[] { new Project { Name = "Halo" } }, | |
Skills = new string[] { "M365", "Azure" }, | |
PartitionKey = "allusers" | |
}; | |
await _containerResponse.Container.CreateItemAsync<User>(user, new PartitionKey(partitionKey)); |
As you can see this is a simple document representing a User object with a few attached properties:
Now in order to only change a few properties in the object, we need to use the Partial document update feature in Azure Cosmos DB
Update document properties
Now lets have a look at how we can modify and add properties to the User object:
//Add new property | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/location", "London") | |
}); | |
//Update existing property | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/name", "Vardhaman Deshpande") | |
}); |
We can also send both properties in a single operation by adding the operations to the patchOperations array.
Update elements in array
//Add new array item at the start | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/skills/0", "Architecture") | |
}); | |
//Add new array item at the specified index | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/skills/2", "Integration") | |
}); | |
//Append new array item at the end of the array | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/skills/-", "B2B SaaS") | |
}); | |
//Update array element at specified index using Set operation | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Set($"/skills/1", "Microsoft 365") | |
}); |
Update objects and their properties
//Update object property from item | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/projects/0/name", "Halo Infinite") | |
}); | |
//Add new item to object array | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Add($"/projects/-", new Project(){ Name="Need for Speed" } ) | |
}); | |
//Remove item at specified index from object array | |
ItemResponse<User> response = await _containerResponse.Container.PatchItemAsync<User>( | |
id: userIdForDemo, | |
partitionKey: new PartitionKey(partitionKey), | |
patchOperations: new[] { | |
PatchOperation.Remove($"/projects/0" ) | |
}); |
Hope this helps! For more details, do have a look at the Microsoft docs for Azure Cosmos DB partial updates: https://docs.microsoft.com/en-us/azure/cosmos-db/partial-document-update
1 comment:
Great Article, thanks for sharing
Post a Comment