fagol
fagol

Reputation: 219

Update field within nested array using mongoose

I'm trying to update the subdocument within the array without success. The new data doesn't get saved.

Express:

router.put('/:id/:bookid', (req, res) => {
  library.findOneAndUpdate(
    { "_id": req.params.id, "books._id": req.params.bookid},
    { 
     "$set": {
        "title.$": 'new title'
      }
    }
}); 

LibraryScema:

const LibarySchema = new Library({
  Name: {
    type: String,
    required: false
  }, 
  books: [BookSchema]
});

bookScema:

const BookSchema = new Schema({

  title: {
    type: String,
    required: false
  },
  Chapters: [
    {
      chapterTitle: {
        type: String,
        required: false
      }
    }
  ]
});

I only aim to update the sub-document, not parent- and sub-document at same time.

Upvotes: 0

Views: 151

Answers (1)

Alex Ironside
Alex Ironside

Reputation: 5069

I had a similar issue. I believe there is something wrong with the $set when it comes to nested arrays (There was an entire issue thread on GitHub). This is how I solved my issue.

var p = req.params;
var b = req.body;

Account.findById(req.user._id, function (err, acc) {
    if (err) {
        console.log(err);
    } else {
        acc.websites.set(req.params._id, req.body.url); //This solved it for me
        acc.save((err, webs) => {
            if (err) {
                console.log(err);
            } else {
                console.log('all good');
                res.redirect('/websites');
            }
        });
    }
});

I have a user with a nested array.

Try this code

router.put('/:id/:bookid', (req, res) => {
    library.findById(
        req.params.id, (err, obj) => {
            if (err) console.log(err); // Debugging
            obj.books.set(req.params.bookid, {
                "title": 'new title',
                'Chapters': 'your chapters array'
            });
            obj.save((err,obj)=>{
                if(err) console.log(err); // Debugging
                else {
                    console.log(obj); // See if the saved object is what expected;
                    res.redirect('...') // Do smth here
                }
            })
        })
});

Let me know if it works, and I'll add explanation.

Explanation: You start by finding the right object (library in this case), then you find the correct object in the array called books.

Using .set you set the whole object to the new state. You'll need to take the data that's not changing from a previous instance of the library object.

I believe this way will overwrite and remove any data that's not passed into the .set() method. And then you save() the changed.

Upvotes: 1

Related Questions