Node.JS – How-To Patch CosmosDB Collections and Nested Items

This will be a bit of a reference guide to updating a CosmosDB collections and nested items in a nice manner. This thread will not cover how to use the CosmosDB package in Node.JS and it will assume you’ve successfully connected to a database.

I will use the example of updating the signature of a user of a forum where that signature is stored in a collection which is the overall thread and then nested collections which are the individual comments.

Example Collection

The collection below will be the example I’m using through this article, this is a simplified representation of a forum post collection –

{
    "lastActivity": 1656354969213,
    "id": "aefe1362-4fe4-4bc7-8d77-8250fa948aaa",
    "title": "Testing!",
    "content": "<p>Hello!</p>",
    "signature": "<p>An amazing signature v15</p>",
    "authorId": 1,
    "comments": [
        {
            "content": "<p>test 2</p>",
            "authorId": 1,
            "commentId": 0,
            "liked": [],
            "author": "Diablo",
            "signature": "<p>An amazing signature v15</p>",
            "disliked": [],
            "date": 1656353275267
        },
        {
            "content": "<p>another</p>",
            "authorId": 1,
            "commentId": 1,
            "liked": [],
            "author": "Diablo",
            "signature": "<p>An amazing signature v15</p>",
            "disliked": [],
            "date": 1656354969213
        }
    ],
    "adminOnlyResponse": false,
    "categoryId": 1,
    "_ts": 1656444244
}

Query for Collections where Property or Nested Propert Equals To

The code below (non-complete) returns just the values of the collections that we want to update or use to update the signature.

// Define a query which returns a collection where authorId or where the "comments" nested collection array contains a record with authorId equal to a given userId
const querySpec = `SELECT r.id, r.categoryId, r.authorId, r.comments, r.signature FROM r WHERE r.authorId = ${userId} OR ARRAY_CONTAINS(r.comments, {"authorId": ${userId}}, true)`

var existingThreads = await this.find(querySpec)

Patch each collection and nested collections

The code below will loop through each thread that is returned by the query above and will also loop through each nested comment collection within that thread record.

If the thread needs to have the signature updated then we will push a new patch operation to the operations array.

Finally if there are any operations required we will then perform a patch operation, updating the original record.

// Loop through all returned threads
existingThreads.forEach(thread => {
    var operations = []

    // If the thread is created by the given user and the signature is different then add a replace patch operation
    if(thread.authorId == userId && thread.signature != newSignature) {
        operations.push({op: 'replace', path:'/signature', value: newSignature})
    }

    // For each comment in thread, update the signature value of each collection array
    thread.comments.forEach((comment, index) => {
        if(comment.authorId == userId && comment.signature != newSignature) {
            operations.push({op: 'replace', path:`/comments/${index}/signature`, value: newSignature})
        }
    })

    // If there are any operations to perform then perform a patch operation
    if(operations.length > 0) {
        // @ts-ignore
        this.container
            .item(
                thread.id,
                thread.categoryId
            )
            // @ts-ignore
            .patch(operations)
    }

})

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.