mongodbmongoose

Why is updateMany not working in my MongoDB / Mongoose-project?


I have made a simple database with some books and some authors. Now I want to update the author-objects with new info. But nothing is happening in the database.

The authors currently looks like this in Postman:

[
    {
        "_id": "663b3c44bcc58cb02031ae33",
        "name": "JRR Tolkien",
        "__v": 0
    },
    {
        "_id": "663b3c44bcc58cb02031ae33",
        "name": "JK Rowling",
        "__v": 0
    }
]

I want to add the line: "country": "UK" to each of them, so I made this endpoint:

app.post("/add-info", (req, res) => {
  try {
    Author.updateMany(
      {},
      {
        $set: {
          country: "UK"
        },
      }
    )

    res.status(201).json({ message: "Info added successfully" })
  } catch (err) {
    res.status(500).json({ error: "Failed to add info" })
  }
})

When using the endpoint to send a post-request I get the "Info added successfully"-message. So nothing wrong there. However, the authors in the database still looks the same. Nothing has been updated! What's wrong?

Update: I've tried handling asynchronous events like this:

app.post("/add-info", async (req, res) => {
  try {
  
    const result = await Author.updateMany({}, { $set: { country: "UK" } })

    res.status(200).json({ message: "Info added successfully", result })
  } catch (err) {
    res.status(500).json({ error: "Failed to add info", details: err.message })
  }
})

The result is:

{
    "message": "Info added successfully",
    "result": {
        "acknowledged": false
    }
}

And nothing is updated in the database.

I've also tried .then like this:

app.post("/add-info", (req, res) => {

  Author.updateMany({}, { $set: { country: "UK" } })
    .then((result) => {
      console.log("Update result:", result)
      console.log(`${result.nModified} users updated`)
    })
    .catch((error) => {
      console.error("Error updating users:", error)
    })
  
})

With this result:

Update result: { acknowledged: false } undefined users updated

Solution

  • The mongoose Model.updateMany method is not the same as the mongodb node.js driver's collection.updateMany.

    Mongoose tries to abstract away some of the boilerplate, so that when you call Model.updateMany you don't need to use $set, that is implied, and the update object passed as the second argument is validate against the schema before submitting the operation to the database.

    In your example, the update part

        {
            $set: {
              country: "UK"
        }
    

    is instructing mongoose to set the value of the field $set to the object country:"UK". I would assume that the schema for the Author model doesn't contain a field named $set, so when this update is validated against the schema, the undefined field is removed, leaving {}, and mongoose skips sending an null operation to the database.

    To accomplish what you want:

    I made a quick example of updateMany:

    const mongoose = require("mongoose")
    
    demoModel = mongoose.model(
       "Demo",
        new mongoose.Schema({
            time: {type: Date, required: true},
            updated: {type: Boolean, required:false}
        }),
    )
    
    async function main() {
        console.log("in main");
        mongoose.connect("mongodb://localhost:27017/test");
        console.log("connected lazily");
    
        let now = new Date();
        await demoModel.create({time: new Date()});
        await demoModel.create({time: new Date()});
        let iresult = await demoModel.find();
        console.log("Insert result:",iresult);
    
        let result = await demoModel.updateMany({},{updated:true});
        console.log("Update Result:",result)
    
        let after = await demoModel.find();
        console.log("Find result:",after);
    
        process.exit();
    }
    
    main();
    

    This resulted in the following output:

    in main
    connected lazily
    Insert result: [
      {
        _id: new ObjectId("66e0d9ed85544caa04f615c1"),
        time: 2024-09-10T23:44:45.091Z,
        __v: 0
      },
      {
        _id: new ObjectId("66e0d9ed85544caa04f615c4"),
        time: 2024-09-10T23:44:45.191Z,
        __v: 0
      }
    ]
    Update Result: {
      acknowledged: true,
      modifiedCount: 2,
      upsertedId: null,
      upsertedCount: 0,
      matchedCount: 2
    }
    Find result: [
      {
        _id: new ObjectId("66e0d9ed85544caa04f615c1"),
        time: 2024-09-10T23:44:45.091Z,
        __v: 0,
        updated: true
      },
      {
        _id: new ObjectId("66e0d9ed85544caa04f615c4"),
        time: 2024-09-10T23:44:45.191Z,
        __v: 0,
        updated: true
      }
    ]