'How to count how many sub-documents have been updated? (mongodb)

I have this fairly simple Chat object:

{
    _id: ObjectId('a4bd8c2f5g19b0a1d1'),
    chatId: 1,
    userId1: 100,
    userId2: 234,
    messages: [
        {msgId: 1, senderId: 100, msgSentOnUnix: 1652046779, msgReadOnUnix: 1652046787, content: 'hello'},
        {msgId: 2, senderId: 100, msgSentOnUnix: 1652046786, msgReadOnUnix: 1652046787, content: 'world'},
        {msgId: 3, senderId: 234, msgSentOnUnix: 1652046795, msgReadOnUnix: -1, content: 'right back...'},
        {msgId: 4, senderId: 234, msgSentOnUnix: 1652046802, msgReadOnUnix: -1, content: 'at you'},
    ]
}

It's a chat between 2 people, with a chatId, both users' IDs, and all their messages. I wish to update many sub-documents, and get the count of how many sub-documents were updated, in one single update query.

To be more specific:

I want to update user XXX's messages as "read" once user YYY enters the "chatroom", and I want to know how many "unread" messages were there. I don't want to do this with 2 queries, as I am concerned with concurrency issues...

Right now, for the update alone (without the count) I use this update command:

db.chats.updateOne(
    {
        userID1: 100,
        userID2: 234,
    },
    {
        $set: {
            'messages.$[i].msgReadOnUnix': $$NOW
        }
    },
    {
        arrayFilters: [
            {
                $and: [ 
                    { 'i.senderID': 234 }, // user 100 is reading users 234's messages
                    { 'i.msgReadOnUnix': -1 }, // -1 Marks that a message is unread
                ]
            }
        ]
    },
)

Could a count be returned as a result here? to state how many sub-documents were modified?



Solution 1:[1]

So I eventually overcame the issue the way @prasad_ had mentioned,
the approach of running the test twice!
Once inside mongoDB, and once on the application level.
I.E. I used findOneAndUpdate({}) to return the document, without the { new: true } property, in order to get the document prior to the update, and then ran the same check that mongo ran:
(i am using node JS)

const { error, errorMsg, data } = await Chat.findOneAndUpdate(
    {
      userID1: 100,
      userID2: 234,
    },
    {
      $set: {
        'messages.$[i].msgReadOnUnix': new Date().getTime(),
      },
    },
    {
      arrayFilters: [
        {
          $and: [{ 'i.senderID': 234}, { 'i.msgReadOnUnix': -1 }],
        },
      ],
    },
  )
    .lean()
    .then((resultSet) => ({ error: false, data: resultSet }))
    .catch((errorMsg) => ({ error: true, errorMsg }));

// running the check again here on the application level ?
for(let i=0; i < ... ; i++){
   // write check logic here and count
}

Since it's the same document coming in it solves the concurrency issue that I was so afraid of. While this works great, can anyone think of a better way? One where I don't have to run my check twice?

Feels like there should be a better way query-wise to be able to solve this...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1