I tried two ways to overwrite an existing document if its not exist.
1st way
This code didn't work and throws this error on every update:
error: *After applying the update to the document {_id: ObjectId('***') , ...}, the (immutable) field '_id' was found to have been altered to _id: ObjectId('***78')"*
exports.loginUser = function (req, res) {
var newUser = new userModel(req.body);
userModel.findOneAndUpdate({email: req.body.email}, newUser ,{ new: true,
upsert:true, setDefaultsOnInsert: true }, function (err, userUpdate) {
return res.json(userUpdate);
}
2nd Way
Directly inserting the request body which work well. But I dont want to do that, because body can have junk:
exports.loginUser = function (req, res) {
var newUser = new userModel(req.body);
userModel.findOneAndUpdate({email: req.body.email}, req.body ,{ new: true,
upsert:true, setDefaultsOnInsert: true }, function (err, userUpdate) {
return res.json(userUpdate);
}
So can anybody suggest me how to do findOneAndUpdate with the model instead of request body.
Use .update() method:
var newUser = new userModel(req.body);
newUser.update(newUser, { upsert:true, setDefaultsOnInsert: true }, function (err) {
if (err) {
console.log(err);
return res.json('Cannot save user');
}
res.json(newUser);
});
There is no need to use the new:true option because newUser will always contain the updated or inserted document
You shouldn't use new because that will create a new _id, so instead you should do:
exports.loginUser = function(req, res) {
var newUser = req.body; // here remove the new
userModel.findOneAndUpdate(
{ email: req.body.email },
newUser,
{ new: true, upsert: true, setDefaultsOnInsert: true },
function(err, userUpdate) {
return res.json(userUpdate);
}
);
}
Related
I'm creating a project using the mern stack. I'm trying to update a project from my frontend to my backend. When I update it it will return success but when I check the database nothing is updated? I'm trying to update the product with the prodID that is entered in the frontend
This is my post route
router.post("/updateStock", (req, res) => {
const prodID = req.body.prodID
const product = new Product(req.body)
Product.findOneAndUpdate(prodID, { new: true }, {returnOriginal: false}, function(err, products) {
if (err) {
console.log("err", err);
res.status(500).send(err);
} else {
console.log("success");
res.send(product);
}
});
});
This is my schema
const mongoose = require("mongoose");
const Product = mongoose.model(
"Product",
new mongoose.Schema({
title: String,
manufacturer: String,
price: String,
catergory: String,
quantity: String,
prodID: String,
images: Array
})
);
module.exports = Product;
Following Mongoose Docs here
1st:
You added filter as a string, however it should've been an object like below
const filter = {prodID: req.body.prodID}
2nd:
no need to instantiate the Product schema, use the update object
const update = req.body
3rd:
You used the same option, also new:true took the place of the update object
returnOriginal: false is equivalent to new: true
4th:
Use promise not callbacks, however you have a typo in the callback you called products and you sent product
Product.findOneAndUpdate(filter, update, {new: true}).then((product) => {
console.log("success");
res.send(product);
}).catch(err => {
console.log("err", err);
res.status(500).send(err);
})
You are not passing the new updated body to findOneAndUpdate. The findOneAndUpdate is expecting db.collection.findOneAndUpdate( filter, update, options ). The code should be like this:-
router.post("/updateStock", (req, res) => {
const product = new Product(req.body);
const filter = {prodID: req.body.prodID}
Product.findOneAndUpdate(filter, product, { new: true, returnOriginal: false}, function(err, products) {
if (err) {
console.log("err", err);
res.status(500).send(err);
} else {
console.log("success");
res.send(product);
}
});
Follow this Schema =>
db.collection.findOneAndUpdate(filter, update, options)
Pass Update object
I have the following route using express and mongoose that update 2 collections from one route. The updates work and are reflected in MongoDb, however, at the end of the request the server crashes with the error: code: 'ERR_HTTP_HEADERS_SENT'. Is there a way for me to avoid this error?
router.post("/user-adopted", verify, (req, res) => {
const userId = req.body.userId;
const petId = req.body.petId;
User.findOneAndUpdate(
{ _id: userId },
{ adoptedPet: petId, petId: false, adoptionRequest: false },
function (err, result) {
if..else..
}
);
Data.findOneAndUpdate(
{ _id: petId },
{ adopted: true },
function (err, result) {
if...else..
);
});
As soon as the User record is updated it performs the operation you have defined in the callback and Data record is left out so to prevent that do the updation of Data record in the callback of user and try to use updateOne() instead of findOneAndUpdate() :
User.updateOne(
{ _id: userId },
{ adoptedPet: petId, petId: false, adoptionRequest: false },
function (err, result) {
if(err) res.send(err)
Data.updateOne(
{ _id: petId },
{ adopted: true },
function (err, result) {
if(err)
res.send(err)
else{
// Redirect where you want to go
}
}
);
}
);
I am developing a web application using MEAN Stack with Angular 6. There if the user previously has added data into the db that data should be updated. For that I used findOneAndUpdate() method. But without updating the existing data it posts another data set into the db.
This is my post route. This 'userName' comes from a different schema.
router.post('/save', function(req, res) {
var mod = new rdaColor(req.body);
rdaColor.findOneAndUpdate(
{
userName: req.body.userName,
colorMovementBox: req.body.colorMovementBox
},
req.body,
{ upsert: true, new: true },
function(err, data) {
if (err) {
console.log(err);
res.send(err);
} else {
res.send(mod);
}
}
);
});
This is schema.
var mongoose = require('mongoose');
// Schema for rda color panel
var rdaColorSchema = new mongoose.Schema({
userName: {
type: String
},
colorMovementBox: {
type: String,
},
});
module.exports = mongoose.model('rdaColor', rdaColorSchema);
This is the output for the following console.log.
console.log("mod"+mod+" "+(req.body));
output
mod{ _id: 5bbd68344619a612b07a688e,
userName: 'abc#yahoo.com',
colorMovementBox: 'rgb(49,64,116)',
} [object Object]
How can I make it only to update the data.
Please check this query.
This will update if data exists with Id and create new if not exists.
If you remove upsert: true then it does not create a new record if not exists.
rdaColor.findOneAndUpdate(
{ _id: "yourId" },
{
$set: {
userName: req.body.userName,
colorMovementBox: req.body.colorMovementBox
}
},
{ upsert: true, new: true },
function(err, doc) {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
}
);
I am trying to update a collection from my database using de node module mongoose. The problem is with $set updates. Here is my code:
// Update a user
app.patch('/user/:user_id', passport.authenticate('bearer', { session: false }),
function (req, res) {
var conditions = { _id: new ObjectId(req.params.user_id)},
updateObj = { $set: req.body }; // {email : "bob#example.com", username: "bob"}
User.update(conditions, updateObj, function callback (err, numAffected, rawResponse) {
if (err) {
res.send(err);
return;
}
// numAffected is the number of updated documents
if (numAffected == 0) {
res.json({ message: 'No user affected'});
return;
}
res.json({ message: 'User updated'});
});
});
If I update an existing key like email, it is updated. But if I want to add a new key, numAffected is always 0 and the rawResponse is undefined.
Any idea of what happens?
Edit
Here is my Schema:
var userSchema = mongoose.Schema({
email : String,
username : String,
password : String
});
In order to set multiple fields in a document, you must set the Multi option in your config, otherwise Mongoose will ignore the continuation, and only update the first doc.
From the docs:
var conditions = { name: 'borne' }
, update = { $inc: { visits: 1 }}
, options = { multi: true };
Model.update(conditions, update, options, callback);
function callback (err, numAffected) {
// numAffected is the number of updated documents
});
Another note here: The numAffected should return as expected, but I can't find any documentation on their site about the raw response, but it should return as expected as well. Do you know of any documentation for this?
I think this is what you really want to do with mongoose to update email and username of a user.
app.patch('/user/:user_id', passport.authenticate('bearer', { session: false }),
function (req, res) {
User.findOneAndUpdate({_id: req.params.user_id},
{
$set: {
username: req.body.username,
email: req.body.email
}
}, function(err, user) {
if (err)
res.send(err);
if (user) {
res.json({message: 'User updated'});
} else {
res.json({message: 'User does not exist'});
}
});
});
I'm trying to update an existing record with Mongoose. The insert is OK but not the update.
Here is my snippet:
app.post('/submit', function(req, res) {
var my_visit = new models.visits({
date: req.body.visit_date,
type: req.body.visit_type,
agency: req.body.visit_agency,
city: req.body.visit_city,
url: req.body.visit_url,
note: req.body.visit_note
});
// INSERT
if(req.body.id == 0) {
my_visit.save(function(err) {
if(err) { throw err; }
console.log('added visit');
res.redirect('/');
});
} else { // UPDATE
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
console.log('updated visit: '+ req.body.id);
res.redirect('/');
});
}
})
The response is Mod on _id is not allowed.
I just want to update the line such as WHERE id = id in MySQL. I didn't find the right syntax.
According to this question and this other one, the Mod on _id is not allowed occurs when one tries to update an object based on its id without deleting it first.
I also found this github issue which tries to explain a solution. It explicitly states:
Be careful to not use an existing model instance for the update clause
(this won't work and can cause weird behavior like infinite loops).
Also, ensure that the update clause does not have an _id property,
which causes Mongo to return a "Mod on _id not allowed" error.
The solution, it seems, is to do the following:
var upsertData = my_visit.toObject();
console.log(req.body.id); // OK
delete upsertData._id;
models.visits.update({ _id: req.body.id }, upsertData, { multi: false }, function(err) {
if(err) { throw err; }
//...
}
On a side note, you can probably rewrite your route to do both the create and update without the if-else clause. update() takes an extra option upsert, which, according to the docs:
upsert (boolean) whether to create the doc if it doesn't match (false)
Here is my solution:
routes/router.js
router.patch('/user/:id', userController.updateUser)
exports.updateUser = async(req, res) => {
const updates = Object.keys(req.body)
const allowedUpdates = ['name', 'email', 'password', 'age']
const isValidOperation = updates.every((update) => allowedUpdates.includes(update))
if (!isValidOperation) {
return res.status(400).send('Invalid updates!')
}
try {
const user = await UserModel.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
if (!user) {
return res.status(404).send()
}
res.status(201).send(user)
} catch (error) {
res.status(400).send(error)
}
}