Updating the document in an array in Mongoose

I have this kind of schema

Schema :

const ReplySchema = new Schema({
  text: String,
  created_on: { type: Date, default: Date.now },
  delete_password: String,
  reported: Boolean
});

const threadSchema = new Schema({
  text: String,
  created_on: { type: Date, default: Date.now },
  bumped_on: { type: Date },
  reported: Boolean,
  delete_password: String,
  replies: [ReplySchema],
  replycount: Number,
});

In database :

So the documents would like this:

{
    "_id": {
        "$oid": "5bfbe4c16c9dc117cb548259"
    },
    "text": "creator",
    "bumped_on": {
        "$date": "2018-11-26T21:32:34.105Z"
    },
    "reported": false,
    "delete_password": "123",
    "created_on": {
        "$date": "2018-11-26T12:19:13.808Z"
    },
    "replies": [
        {
            "_id": {
                "$oid": "5bfc665f4c5b42266f972c0d"
            },
            "text": "index",
            "delete_password": "111",
            "reported": false,
            "created_on": {
                "$date": "2018-11-26T21:32:15.842Z"
            }
        },
        {
            "_id": {
                "$oid": "5bfc66664c5b42266f972c0e"
            },
            "text": "steve",
            "delete_password": "111",
            "reported": false,
            "created_on": {
                "$date": "2018-11-26T21:32:22.659Z"
            }
        }
    ],
    "__v": 0
}

Handler :

So as on the project of anonymous board. We have to delete a reply on a thread.

 this.removeReply = function(req, res){
    const board = req.params.board;
    const body = req.body;
    const thread_id = req.body.thread_id;
    const reply_id = req.body.reply_id;
    const delete_password = req.body.delete_password;

    const threadModel = `${board.toLowerCase().trim().split(' ').join('')}-board`;
    
    const Thread = mongoose.model(threadModel, threadSchema);
    
    Thread
      .findOneAndUpdate(
        { _id: thread_id }, // conditions
        {},                 // update
        { fields:           // options
           { 
              replies: 
                { 
                  $elemMatch: 
                    { 
                      _id: reply_id,
                      delete_password: delete_password
                    } 
                } 
           } 
        }
      )
      .exec((err, docs) => {
        console.log(docs);
      })
  }

As you can see I didn’t set anything on the update {} to find out what is the document it will return.

Test :

My mocha test is:

  it('DELETE', (done) => {
    chai.request(server)
      .delete('/api/replies/dummy')
      .type('form')
      .send({
        "board": "dummy",
        "thread_id": "5bfbe4c16c9dc117cb548259",
        "reply_id": "5bfc665f4c5b42266f972c0d",    // correct
        "delete_password": "111"
      })
      .end((err, res) => {
        done();
      })
  });

Result :

It returns the correct document.

{ _id: 5bfbe4c16c9dc117cb548259,
  replies: 
    [ { created_on: 2018-11-26T12:19:13.808Z,
        _id: 5bfc665f4c5b42266f972c0d,
        text: 'index',
        delete_password: '111',
        reported: false } ] }

Problem :

The problem is when I set the update to { $set: { 'replies.$.text': '[deleted]' } }, it returns undefined.

Use filtered positional operator $[<identifier>] instead. More info here.

The solution must be

    Thread
      .findOneAndUpdate(
        { _id: thread_id },
        { $set: { "replies.$[elem].text": "[deleted]" } },
        { arrayFilters: [ { 
            "elem._id": new mongoose.Types.ObjectId(reply_id), 
            "elem.delete_password": delete_password 
          } ], 
         new: true },
      )
      .exec((err, docs) => {
        docs.replies.forEach((elem) => {
          if (elem._id == reply_id){
            if (elem.text === '[deleted]'){
              return res.send('sucess'); 
            }
            return res.send('incorrect password');
          }
        })
      })