Surya Varma
Surya Varma

Reputation: 33

How to update specific child value within a document in cosmos db using c#?

I have a document in cosmos db that needs to be updated similar to the below doc

{
    "userId": "1234",
    "values": {
        "A": {
            "description": "first description",
            "timestamp": "2018-10-01T12:13:09.000Z",
            "value": 5000,
            "valueWithUnit": "202 W"
        },
        "B": {
            "description": "second description",
            "timestamp": "2018-10-01T12:13:09.000Z",
            "value": 2,
            "valueWithUnit": "2.00 %"
        }
     },
    "id": "1",
    "lastUpdate": "2018-09-20T14:39:00Z",
    "_rid":  "rid",
    "_self": "self",
    "_etag": "etag",
    "_attachments": "attachments/",
    "_ts": 1234
}

I need to update the value within 'B' from 2 to 3.

Below is the code I have so far..

public DocumentClient client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey);

var collectionLink = UriFactory.CreateDocumentCollectionUri(databaseName, collectionName);

Document doc = client.CreateDocumentQuery<Document>(collectionLink)
            .Where(r => r.Id == "1")
            .AsEnumerable()
            .SingleOrDefault();

Document doc1 = doc.GetPropertyValue<Document>("values");

Document doc2 = doc1.GetPropertyValue<Document>("B");

doc2.SetPropertyValue("value", 3);

How do I now update the document to reflect the new property values in cosmosdb?

Any help will be hugely appreciated

Upvotes: 3

Views: 2461

Answers (1)

Nick Chapsas
Nick Chapsas

Reputation: 7200

There are multiple ways to do this. If you don't want to do any specific object mapping and you just wanna work with json then your code should look like this:

public DocumentClient client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey);

var collectionLink = UriFactory.CreateDocumentCollectionUri(databaseName, collectionName);

Document doc = client.CreateDocumentQuery<Document>(collectionLink)
            .Where(r => r.Id == "1")
            .AsEnumerable()
            .SingleOrDefault();

var docValues = doc.GetPropertyValue<dynamic>("values");
docValues.B.value = 3;
doc.SetPropertyValue("values", docValues);

await documentClient.ReplaceDocumentAsync(doc);

If you used the Document object with the GetPropertyValue method you would also add all the document metadata which is not what you wanna do.

Keep in mind that if your collection is partition then you also need to provide the partition key by replacing like this:

await documentClient.ReplaceDocumentAsync(doc, new RequestOptions{PartitionKey = new PartitionKey("partitionKeyValueHere")});

You can also use UpsertDocumentAsync which will insert if the document doesn't exist and update if it does exist.

var documentLink = UriFactory.CreateDocumentUri(databaseName, collectionName, "1");
await documentClient.UpsertDocumentAsync(documentLink, doc);

And if the collection is partitioned:

var documentLink = UriFactory.CreateDocumentUri(databaseName, collectionName, "1");
await documentClient.UpsertDocumentAsync(documentLink, doc, new RequestOptions{PartitionKey = new PartitionKey("partitionKeyValueHere")});

You can also speed up your querying logic by turning it into a direct read.

You can simply get the document using it's id by doing this:

var docUri = UriFactory.CreateDocumentUri(databaseName, collectionName, "1");
Document doc = await productStore.CosmonautClient.DocumentClient.ReadDocumentAsync(docUri);

If your collection is partitioned you will need the RequestOptions object with the partition key value as your partition key for this document.

This is both faster and cheaper.

Upvotes: 2

Related Questions