Unfortunately, there isn't a way to use some sql like syntax to update a specific child array item using a condition. You have to know the index to it. That means you need to pull down your document (you can select only the fields you need to do this work).
This is verbose, but it's really not doing a whole lot once you read through it.
Document:
{
"id": "15bab994-6ea2-436c-badd-a31f44d2e85d",
"conversationId": "5663d3ff-1347-4413-a584-9c634425c7ab",
"subject": "Office credit card",
"dateSent": "2022-06-08",
"dateCreated": "2022-06-06",
"isRetracted": false,
"parentId": "",
"isDeletedForSender": true,
"sender": {
"emailAddress": "[email protected]",
"isUnread": true
},
"recipients": [
{
"id": 2,
"emailAddress": "[email protected]",
"type": 2,
"isUnread": true,
"labelIds": [
2
]
},
{
"id": 1,
"emailAddress": "[email protected]",
"type": 1,
"isUnread": true,
"labelIds": [
1
]
}
],
"attachments": [
{
"name": "card.pdf",
"sizeInBytes": 129323
}
],
"_rid": "zl9jANa86aABAAAAAAAAAA==",
"_self": "dbs/zl9jAA==/colls/zl9jANa86aA=/docs/zl9jANa86aABAAAAAAAAAA==/",
"_etag": "\"0d0093b8-0000-0100-0000-62a57c470000\"",
"_attachments": "attachments/",
"recipients[0].isUnread": true,
"_ts": 1655012423
}
Conditional patch code to update isUnread
for sender or recipients that match a specific email.
var container = _cosmosClient.GetContainer("my-database", "Message");
// Get all of the messages that match the list of conversations to update
var queryResultSetIterator = container.GetItemLinqQueryable<Message2>()
.Select(x => new PatchMessageContainer
{
Id = x.Id,
ConversationId = x.ConversationId,
Recipients = x.Recipients,
Sender = x.Sender
})
.Where(x => payload.ConversationIds.Contains(x.ConversationId)).ToFeedIterator();
var conversations = new List<PatchMessageContainer>();
while (queryResultSetIterator.HasMoreResults)
conversations.AddRange(await queryResultSetIterator.ReadNextAsync().ConfigureAwait(false));
// Set isUnread for the authenticated user in the recipients list
var updateTasks = new List<Task>();
foreach (var conversation in conversations)
{
// The following Patch operations are smart enough to skip if the target value is already set to the desired value
var patchOpts = new List<PatchOperation>();
// Update sender isUnread if sender matches auth email
if (conversation.Sender.EmailAddress == userClaims.Email && conversation.Sender.IsUnread != payload.SetIsUnread)
patchOpts.Add(PatchOperation.Set($"/sender/isUnread", payload.SetIsUnread));
// Update recipient isUnread where recipient matches auth email
var idx = conversation.Recipients.FindIndex(x => x.EmailAddress == userClaims.Email);
if (idx > -1 && conversation.Recipients[idx].IsUnread != payload.SetIsUnread)
patchOpts.Add(PatchOperation.Set($"/recipients/{idx}/isUnread", payload.SetIsUnread));
// Send the actual patch request
var task = container.PatchItemAsync<Message2>(conversation.Id.ToString(),
new PartitionKey(conversation.ConversationId.ToString()), patchOpts);
updateTasks.Add(task);
}
await Task.WhenAll(updateTasks);
conversations
variable here is really just the Message document in the first code block, but I've only selected a subset of fields needed to accomplish the update.
Hope this helps.