Q:

Mongoose instance .save() not working when embedded array object changed

I am using Mongoose npm module to manage mongodb.
This is schema of mongodb collection what I am going to update.
var UserSchema = new Schema({
    username: {
        type: String,
        unique: true,
        required: true
    },
    email: {
        type: String,
        unique: true,
        required: true
    },
    cards: []
});
module.exports = mongoose.model('User', UserSchema);

inside post request, here req is request object of post request.
 and res is response object.
User.findById(userID).exec(function (err, doc) {
        let cardInfo = req.cardInfo
        let cardIndex = req.cardIndex
        doc["cards"][0] = cardInfo;
        console.log(doc)
/*  here I got right doc object as I requested
{
        "_id": "59f3bdd488f912234fcf06ab",
        "email": "test@gmail.com",
        "username": "test",
        "__v": 2,
        "cards": [
            {
                "testNo": "42424242424242"
            }
        ]
    }
*/
        doc.save(function (err) {
          if (err) {
            return res.json({
              success: false,
              msg: 'Card add error'
            });
          }
          res.json({
            success: true,
            msg: 'Successful updated card.'
          });
        });
})

I got message 'Successful updated card.', but actually, It doesn't save.
How to solve it. Thanks.

A:

The problem is that mongoose don't knwo your array is modified.
You can use 2 solutions :
markModified
This function will mark the embedded element as modified and force a resave of it.
It will tell mongoose to resave this element.
User.findById(userID).exec(function (err, doc) {
        let cardInfo = req.cardInfo
        let cardIndex = req.cardIndex
        doc["cards"][0] = cardInfo;
        console.log(doc)
/*  here I got right doc object as I requested
{
        "_id": "59f3bdd488f912234fcf06ab",
        "email": "test@gmail.com",
        "username": "test",
        "__v": 2,
        "cards": [
            {
                "testNo": "42424242424242"
            }
        ]
    }
*/
        doc.markModified('cards');
        doc.save(function (err) {
          if (err) {
            return res.json({
              success: false,
              msg: 'Card add error'
            });
          }
          res.json({
            success: true,
            msg: 'Successful updated card.'
          });
        });
})

Use a full schema.
To avoid the markModified trick, you should describe the content of cards in your schema. This way mongoose will be able to determine if it needs to save the field or not.
Here is the way to declare your schema properly :
const CardSchema = new Schema({
  testNo: String,
});

var UserSchema = new Schema({
    username: {
        type: String,
        unique: true,
        required: true
    },
    email: {
        type: String,
        unique: true,
        required: true
    },
    cards: [CardSchema]
});
module.exports = mongoose.model('User', UserSchema);

This way, mongoose will be able to detect if a value inside cards changed and save only the modified item. 
If you can do it (static schema), this is clearly the good way to do it.

