Data Operations In Cosmos DB - Part 1
In a previous article we explored ways to automate the creation of database and container in Cosmos DB in the console application.
In this article, we will discuss different methods to perform various data operations in a Cosmos DB container.
Set Up
Lets start by first declaring a record object that defines the properties of the document to be added.
public record ProductRecord(
string id,
string ProductName,
string ProductCategory,
string ProductRegion,
int Quantity,
string[] PastQuantity,
Suppliers[] Suppliers
);
public class Suppliers
{
public string SupplierName { get; set; }
public string SupplierCity { get; set; }
}
The object has the following properties :
id
>> Unique GUIDProductName
>> Name of the productProductCategory
>> Category of the productProductRegion
>> Region of the product. Remember this also is a partition keyQuantity
>> Given quantity of the productPastQuantity
>> Past quantity of the product. It is a collectionSuppliers
>> Supplier details like Name & City. This property is an array and can have multiple values
Note : We will use Transactional batch class to perform multiple entry operations in a single batch and insert two documents in the container through the same batch.
public static async Task<bool> AddNewProducts()
{
string id = Guid.NewGuid().ToString();
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ProductRecord firstitem = new(
id: id,
ProductName: "product1",
Suppliers: new Suppliers[] { new Suppliers { SupplierName = "SupplierForProduct1", SupplierCity = "SupplierCity1" } },
ProductCategory: "category1",
ProductRegion: partitionvalue,
Quantity: 11,
PastQuantity: new string[] { "5", "2" });
id = Guid.NewGuid().ToString();
ProductRecord secondItem = new(
id: id,
ProductName: "product2",
Suppliers: new Suppliers[] { new Suppliers { SupplierName = "SupplierForProduct2", SupplierCity = "SupplierCity2" } },
ProductCategory: "category2",
ProductRegion: partitionvalue,
Quantity: 6,
PastQuantity: new string[] { "10", "14" });
TransactionalBatch batch = container.CreateTransactionalBatch(partitionKey)
.CreateItem<ProductRecord>(firstitem)
.CreateItem<ProductRecord>(secondItem);
using TransactionalBatchResponse response = await batch.ExecuteAsync();
return response.IsSuccessStatusCode;
}
Lets break down the code :
Auto create the Guid
which sets the values for id property .The partition is set for region called region1
. Remember that our partition key is on ProductRegion
.
string id = Guid.NewGuid().ToString();
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
Declare a record named firstitem
and set the properties and assign it to the ProductRecord
object.
ProductRecord firstitem = new(
id: id,
ProductName: "product1",
Suppliers: new Suppliers[] { new Suppliers { SupplierName = "SupplierForProduct1", SupplierCity = "SupplierCity1" } },
ProductCategory: "category1",
ProductRegion: partitionvalue,
Quantity: 11,
PastQuantity: new string[] { "5", "2" });
Declare a second record named secondItem
and set its properties and assign it to ProductRecord
object similar to how we did with firstitem
.
id = Guid.NewGuid().ToString();
ProductRecord secondItem = new(
id: id,
ProductName: "product2",
Suppliers: new Suppliers[] { new Suppliers { SupplierName = "SupplierForProduct2", SupplierCity = "SupplierCity2" } },
ProductCategory: "category2",
ProductRegion: partitionvalue,
Quantity: 6,
PastQuantity: new string[] { "10", "14" });
Next, create a transaction batch and then assign the two created record items to a single transaction batch called batch
for inserting into the container.
TransactionalBatch batch = container.CreateTransactionalBatch(partitionKey)
.CreateItem<ProductRecord>(firstitem)
.CreateItem<ProductRecord>(secondItem);
using TransactionalBatchResponse response = await batch.ExecuteAsync();
return response.IsSuccessStatusCode;
Executing the method inserts 2 documents in the container
Will use the id with value : e7be6237-29f6-4077-84f2-95d6d75c4045
to demonstrate further operations. For that purpose a static string variable called id
is declared that holds this value .
static string id = "e7be6237-29f6-4077-84f2-95d6d75c4045";
Method that updates a category name :
public static async Task<string> UpdateProductDetails()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: "e7be6237-29f6-4077-84f2-95d6d75c4045",
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Replace($"/ProductCategory", "Category2")
});
return response.StatusCode.ToString();
}
Values before and after update :
Method that updates supplier name property in the supplier array.
public static async Task<string> UpdateSuppliertDetails()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Replace($"/Suppliers/0/SupplierName", "SupplierForProductOne")
});
return response.StatusCode.ToString();
}
Values before and after update :
Method that adds a new supplier details to the supplier array
public static async Task<string> AddNewSupplierDetails()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Add("/Suppliers/-",new Suppliers { SupplierName = "SecondSupplierForProductOne", SupplierCity = "SupplierCity2" })
});
return response.StatusCode.ToString();
}
Values before and after the add operation :
Method that adds a new entry to the PastQuantity
array
public static async Task<string> AddNewPastQuantity()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Add($"/PastQuantity/0", "100")
});
return response.StatusCode.ToString();
}
Note : We define an index position 0 of the array to insert the value in the array.
PatchOperation.Add($"/PastQuantity/0", "100")
Values before and after the add operation :
Update an existing value of PastQuantity
public static async Task<string> UpdatePastQuantity()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Replace($"/PastQuantity/0", "110")
});
return response.StatusCode.ToString();
}
Note : Similar to the add operation we define an index position 0 of the array to identify the value that needs to be updated.
PatchOperation.Replace($"/PastQuantity/0", "110")
PastQuantity
value of 100 is updated to 110
Delete the newly added supplier
public static async Task<string> DeleteSupplierDetails()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Remove("/Suppliers/1")
});
return response.StatusCode.ToString();
}
Note : We define an index position 1 of the array to identify the value that needs to be deleted.
PatchOperation.Remove("/Suppliers/1")
Pre and post delete
Delete the newly added PastQuantity
value of 100
public static async Task<string> DeletePastQuantity()
{
string partitionvalue = "region1";
PartitionKey partitionKey = new(partitionvalue);
ItemResponse<ProductRecord> response = await container.PatchItemAsync<ProductRecord>(
id: id,
partitionKey: new PartitionKey(partitionvalue),
patchOperations: new[] {
PatchOperation.Remove($"/PastQuantity/0")
});
return response.StatusCode.ToString();
}
Note : We define an index position 0 of the array to identify the value that needs to be deleted.
PatchOperation.Remove($"/PastQuantity/0")
Pre and post delete
Closing Notes :
In conclusion, we saw how to leverage the full potential of this powerful NoSQL database. Understanding the methods and techniques of the fundamental data operations that were discussed above is crucial. I hope this article has provided valuable insights and practical knowledge to help use Cosmos DB in real life project.
In the next article I will continue to delve into the features related to data retrieval in Cosmos DB.
Happy learning !
Subscribe to my newsletter
Read articles from Sachin Nandanwar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by