Vaggelis
Vaggelis

Reputation: 1011

How to run callback after mongoose findOneAndUpdate finish updating?

In my API i have the express's app.put method,where i search in a collection for a document with a specific title with mongoose's findOneAndUpdate method and update it.


    app.put("/articles/:articleTitle",(req, res) => {

        Article.findOneAndUpdate({
               title: req.params.articleTitle
           }, {
               title: req.body.title,
               content: req.body.content
           }, (err, foundArticle) => {
               err ? res.send("Error !") : foundArticle ? res.send("Article found.Updating...") : res.send("NO articles found to update!")
           })

       })

How can i run a callback function AFTER the update has finished,and maybe return the updated document ? I have tried to add a .then at the end of findOneAndUpdate method but it throws me this error : "MongooseError: Query was already executed: Article.findOneAndUpdate..."

I have also tried to pass the method's return value in a variable and access it in .then but it throws the same error like so :


    app.put("/articles/:articleTitle",(req, res) => {
        
       const doc = Article.findOneAndUpdate({
               title: req.params.articleTitle
           }, {
               title: req.body.title,
               content: req.body.content
           },{returnDocument: 'after'}, (err, foundArticle) => {
               err ? res.send("Error !") : foundArticle ? res.send("Article found.Updating...") : res.send("NO articles found to update!")
           }).then( () =>{ console.log(doc) })
           
       })

EDIT : It seems that when i simply add the option returnDocument: 'after' as a parameter,it gives me access to the "after" document inside its own method callback,hmm,i have to check the docs but if anyone knows the common practice to do this i would appreciate it !


        Article.findOneAndUpdate({
            title: req.params.articleTitle
        }, {
            title: req.body.title,
            content: req.body.content
        },{returnDocument: 'after'}, (err, foundArticle) => {
            err ? res.send("Error !") : foundArticle ? res.send(foundArticle) : res.send("NO articles found to update!")
        })

Upvotes: 0

Views: 918

Answers (1)

bajro
bajro

Reputation: 1250

According to the docs, findOneAndUpdate():

[...] finds the first document that matches a given filter, applies an update, and returns the document. By default, findOneAndUpdate() returns the document as it was before update was applied.

To actually return the updated document, the documentation suggests to do the following:

You should set the new option to true to return the document after update was applied.

The third argument to the method is an optional options object where a new parameter can be set to true in order to actually return the updated document.

To actually access the updated document after the method call, there are multiple ways of doing so.

Example 1: Using async/await syntax

const doc = await Article.findOneAndUpdate(
    { title: req.params.articleTitle },
    {
        title: req.body.title,
        content: req.body.content
    },
    { new: true }
)

doc.title // equals value of req.body.title

Example 2: Using .then() syntax

Article.findOneAndUpdate(
    { title: req.params.articleTitle },
    {
        title: req.body.title,
        content: req.body.content
    },
    { new: true }
).then((err, doc) => {
    console.log(doc.title) // equals value of req.body.title
})

Example 3: Using the callback syntax

Article.findOneAndUpdate(
    { title: req.params.articleTitle },
    {
        title: req.body.title,
        content: req.body.content
    },
    { new: true },
    (err, doc) => {
        console.log(doc.title) // equals value of req.body.title
    })

Upvotes: 1

Related Questions