'Mongoose: multi: true for a projection update doesn't work?

Having a document with the following structure:

{
   _id: { type: mongoose.Schema.Types.ObjectId, ref: 'Story' },
   notifications: [{
      story: {
         _id: { type: mongoose.Schema.Types.ObjectId, ref: 'Story' },
         video_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Video' }
      },
      video: {
         _id: { type: mongoose.Schema.Types.ObjectId, ref: 'Video' },
         video_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Video' }
      },
      type: { type: String },
      read: { type: Number, default: 0 }, // 0 - Unread, 1 - read
      ts: { type: Date, default: Date.now }
    }]
}

I'm trying to mark as read all notifications which read element equals to 0, but for any reason, my code only modifies the first notification:

mongoose.model('User').update({ _id: user_id, 'notifications.read': 0 }, { $set: { 'notifications.$.read': 1 }}, { multi: true });

Am I using correctly the multi: true?

UPDATE

I'd say what I'm trying to do, doesn't have any sense by using the placeholder since as the doc says:

$. Acts as a placeholder to update the first element that matches the query condition in an update.



Solution 1:[1]

When you use { _id: user_id, 'notifications.read': 0 } this to update the document, it will only find one document, because you are querying by the _id.

You should use {'notifications.read': 0 } instead.

Solution 2:[2]

You must use the $ placeholder, but to modify multiple embedded documents in one query it's necessary to use the arrayFilters as well, as specified here. Also, you don't have to use multi: true.

In your case it would look like this:

mongoose.model('User').updateOne(
    { _id: user_id },
    { $set: { 'notifications.$[element].read': 1 } },
    { arrayFilters: [{ 'element.read': 0 }] }
)

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 Dhanush Gopinath
Solution 2 Ernani