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
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
}
]