I have an issue I've not seen before with the Mongoose findByIdAndUpdate not returning the correct model in the callback.
Here's the code:
var id = args._id;
var updateObj = {updatedDate: Date.now()};
_.extend(updateObj, args);
Model.findByIdAndUpdate(id, updateObj, function(err, model) {
if (err) {
logger.error(modelString +':edit' + modelString +' - ' + err.message);
self.emit('item:failure', 'Failed to edit ' + modelString);
return;
}
self.emit('item:success', model);
});
The original document in the db looks like this:
{
_id: 1234
descriptors: Array[2],
name: 'Test Name 1'
}
The updateObj going in looks like this:
{
_id: 1234
descriptors: Array[2],
name: 'Test Name 2'
}
The model returned from the callback is identical to the original model, not the updatedObj.
If I query the db, it has been updated correctly. It's just not being returned from the database.
This feels like a 'stupid-user' error, but I can't see it. Any ideas greatly appreciated.
In Mongoose 4.0, the default value for the new option of findByIdAndUpdate (and findOneAndUpdate) has changed to false, which means returning the old doc (see #2262 of the release notes). So you need to explicitly set the option to true to get the new version of the doc, after the update is applied:
Model.findByIdAndUpdate(id, updateObj, {new: true}, function(err, model) {...
app.put("/vendor/:id",async (req,res)=>{
res.send(req.params)
await ModelName.findByIdAndUpdate(id, {type: change}, function(err, docs){
if(err){
conslole.log(err)
}else{
console.log(docs)
}
})
})
Example:
app.put("/vendor/:id",async (req,res)=>{
res.send(req.params)
const data = await userModel.findByIdAndUpdate(req.params.id, {isVendor: true},
function(err, docs){
if(err){
conslole.log(err)
}else{
console.log(docs)
}
})
})
Related
Consider the following code on NodeJS for updating a Document By id:
router.put('/:orderId', async(req, res) => {
let update_orderId = req.params.orderId;
let new_item = req.body.item;
let new_item_desc = req.body.item_desc;
let new_quantity = req.body.quantity;
let new_unit_price = req.body.unit_price;
let new_total_cost = new_quantity * new_unit_price;
let new_status = req.body.status;
let new_priority = req.body.priority;
await RequestPermissionOrderSchema.findByIdAndUpdate( update_orderId, {
$set: {
item: new_item,
item_desc: new_item_desc,
quantity: new_quantity,
unit_price: new_unit_price,
total_cost: new_total_cost,
status: new_status,
priority: new_priority,
directOrder: false
}
},
{ new: true, useFindAndModify: false}, function (err, docs) {
if (err) {
console.log(err);
res.send(err);
} else {
console.log("Updated Request Permission Order : ", docs);
res.json(docs);
}
});
});
Everything is according to the latest documentation of Mongoose 5.10.9 and the schema also contains all the properties specified under $set: { ... } . But when I execute, I get the output as follows in the console:
updated Request Permission Order : null
I also make sure of whether the _id is available in the mongoDB database and that object ID is there. I can't seem to find what I did wrong. Really appreciate any help on this !
Also, note that I want to update by the _id auto-generated by MongoDB with each document.
Just pass the JSON object, remove the $set
await RequestPermissionOrderSchema.findByIdAndUpdate( update_orderId, {
$set: { // REMOVE THIS $set
item: new_item,
item_desc: new_item_desc,
quantity: new_quantity,
unit_price: new_unit_price,
total_cost: new_total_cost,
status: new_status,
priority: new_priority,
directOrder: false
} // REMOVE THIS ALSO
},
Only the JSON object.
i'm working in a node project and need help.
I have callback function, that executes the method findOne, have o result, but I can't change a property of the result.
Ex. Data
{
name: "John",
age: 30,
}
Ex. Callback Function.
this._userRepository.findOne({}, (err, user) => {
if (err) {
return callback({ code: 404, message: "User not found" }, []);
}
user.name = "edson";
return callback("", user);
});
But user name not change in the return.
Ex. Result
{
name: "John",
age: 30,
}
Expected outcome
{
name: "edson",
age: 30,
}
You need to use user.save() before returning anything as given below,
user.name = "edson";
user.save();
return callback("", user);
OR use findOneAndUpdate() as given below
const filter = {};
const update = { name : "edson"};
this._userRepository.findOneAndUpdate(filter, update, {upsert: true}, function(err, doc) {
if (err) return res.send(500, {error: err});
return res.send('Succesfully saved.');
});
Refer https://mongoosejs.com/docs/tutorials/findoneandupdate.html for further details
are you actually trying to update the value of the user in your database? If so, I think you would need to call user.save()
Try wrapping your code in an async function, then running the following code
await this._userRepository.findOneAndUpdate({}, {$set: { name: 'edson' }});
The findOneAndUpdate method takes a filter and an object wrapped in a $set key. This method is a lot quicker.
I want to query a collection and update each document using some value that i will get from another query which is gonna be built with some info from the returned document.
const mongoose = require('mongoose');
const userModel = {
country: { type: String }
newField: { type: String }
};
const myUsersModel = mongoose.model('user',userModel);
myUsersModel.find({country:"USA"}).forEach(function (doc) {
// another query here into a relation Database:
let anotherQuery = 'SELECT * FROM myTable WHERE name=' + doc.name;
mySQLConnection.query(
anotherQuery,
function selectCb(err, results, fields) {
if (err) {
console.log("ERROR: " + err.message);
throw err;
}
console.log("Got "+results.length+" Rows:");
let updatedInfo = results.SomeField;
// update the mongoose doc:
doc.newField = updatedInfo;
myUsersModel.save(doc);
});
mySQLConnection.end(function(err) {
console.log("connection ended.");
});
mongoose.connection.close();
});
I am getting the following error:
TypeError: myUsersModel.find(...).forEach is not a function
myUsersModel.find({country:"USA"})
.then(users=>users.forEach //users might be null here btw
Or if you want to keep your callback style
myUsersModel.find({country:"USA"}, function(err, users) {
if (err) throw err;
users.forEach
If a callback is not provided, Model.find returns an instance of Query and not an instance of Array.
Hence, you can not use forEach as Query is not an Array.
I have this mongoose schema:
var listingSchema = new Schema({
street : String,
buildingNumber : Number,
apartmentNumber : Number,
UsersAndQuestions: [{
userID: String,
questionID: [String]
}]
});
And I just want to update it with a new entry to UsersAndQuestions which will consist of a userID which is a String, and a questionID which is also a String (but needs to be inserted into an array).
I am using this PUT request:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid')
So I have all the necessary parameters in hand.
Usually, when I wanted to update a field in a schema I used this code that I wrote:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addReportedUser/:userid/:listingid', function (req, res) {
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {reportedUsersIDs: ObjectId(idToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the reportedUserID to the listing" + err);
}
else {
console.log("Success adding reportedUserID to listing!");
}
})
});
You can see I used $addToSet and it worked well. But now I want to add two parameters to a field which is an array. I thought about doing something like this:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid', function(req,res){
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
var questionToAdd = req.params.questionid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions.userID : ObjectId(idToAdd), UsersAndQuestions.questionID : ObjectId(questionToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the user and question to the listing" + err);
}
else{
console.log("Success adding user and question to the listing!");
}
})
});
But I'm obviously getting a SyntaxError.
What is the correct syntax for doing what I tried to do?
Thanks a lot! :)
You need to add object to set UsersAndQuestions:
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }}
UPDATE.
I would do it with two queries:
Listing.update({_id: ObjectId(listingToUpdate), 'UsersAndQuestions.userID': idToAdd},
{"$addToSet": {"UsersAndQuestions.$.questionID": questionToAdd}}
, function (err, result) {
if(result.n === 0){
//we haven't found document with the userId - idToAdd
//we need to insert to UsersAndQuestions document with this user
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }},
function(err, res){
})
}
})
As the title suggests I'm having problems with mongoose save method, which fails but does not produce an error.
I actually know why it fails, which is down to the userId field being marked as required but not being provided... but I don't know why it doesn't throw an error. I've exhausted google and stackoverflow looking at similar suggestions with no luck, so throwing it open to anyone who can help me!
Here's the code...
Model.js
var mongoose = require('mongoose');
var TimeSchema = new mongoose.Schema({
client: String,
matter: String,
activity: String,
tags: String,
description: String,
comments: [String],
startTime: Date,
startTimeUTC: Number,
endTime: Date,
endTimeUTC: Number,
duration: Number,
durationRnd: Number,
durationUnits: Number,
billable: Boolean,
rate: Number,
total: Number,
user: String,
userId: { type: mongoose.Schema.ObjectId, required: true }
}, {safe: true});
mongoose.model("Time", TimeSchema);
Controller.js
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
time.save(function (err) {
if (err) { res.send({'error' : err}); }
res.send(time);
});
}
EDIT - To clarify the callback is being called, take the following code for example.
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
console.log("time = " + time);
// TODO user
time.save(function (err) {
if (err) { handleError(res, err); }
console.log("ok");
Time.findById(time._id, function (err, found) {
console.log("found = " + found);
});
res.send(time);
});
}
and here's the console output
Adding time: {"description":"test","client":"","matter":"","activity":"","rate":
"","startTime":"2013-11-30T19:58:43.000Z","startTimeUTC":"1385841523000","endTim
e":"2013-11-30T19:58:45.000Z","endTimeUTC":"1385841525000","startLocale":"19:58"
,"startTimeLocale":"19:58:43","endLocale":"19:58","endTimeLocale":"19:58:45"}
time = { description: 'test',
client: '',
matter: '',
activity: '',
rate: null,
startTime: Sat Nov 30 2013 19:58:43 GMT+0000 (GMT Standard Time),
startTimeUTC: 1385841523000,
endTime: Sat Nov 30 2013 19:58:45 GMT+0000 (GMT Standard Time),
endTimeUTC: 1385841525000,
startTimeLocale: '19:58:43',
endTimeLocale: '19:58:45',
_id: 529a43750a366b6419000001,
comments: [] }
ok
POST /api/times 200 14ms - 313b
found = null
It is very possible to run into this error by naively not connecting to the database. Has happened several times to me. Make sure your mongoose.connect() is in place.
Problem solved, thanks to robertkelp.
Here's my revised code in case if ever helps anyone, but it appears the error was being thrown I just wasn't handling it correctly.
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
time.save(function (err) {
if (err) {
handleError(res, err);
}
else {
res.send(time);
}
});
}
My Problem was not solved by using findOne, it was solved by defining the fields i updated , in the model schema. so my code was like that:
User.findOne({email:data.userData.email}, function (err, user) {
if (!err && user!=undefined){
console.log(user);
var userDiscounts = user.discounts;
for(var i=0;i<userDiscounts.length;i++){
if (userDiscounts[i]!=undefined && userDiscounts[i].code=="XXXXXX"){
userDiscounts[i].claimed = true;
console.log('discount claimed');
}
}
user.discounts = userDiscounts;
user.fbDiscountClaimed = true;
user.save(function(err) {
if (err) console.log(err);
console.log('Saved Hashve-FB as claimed');
});
}
});
}
}
But the schema of the discount and user model was missing the definition of types of user.discounts so i added the following:
var UserSchema = new Schema({
name: String,
email: { type: String, lowercase: true },
role: {
type: String,
default: 'user'
},
hashedPassword: String,
provider: String,
salt: String,
messages:[],
discounts:[{
"name": String,
"description": String,
"created_at": String,
"updated_at": String,
"code": String,
"claimed": Boolean
}
],
facebook: {},
fbDiscountClaimed:false,
twitter: {},
google: {},
github: {}
});
UserSchema.pre('save',function(next){
var currentDate=new Date();
this.updatedAt=currentDate;
if(!this.createdAt){
this.createdAt=currentDate;
};
next();
});
When I use the .pre('save',fn) to create time, I forgot the next(), causing the data store to fail without error,I hope can help somebody!
For anyone can face a similar issue, I found that when populating a mongoose schema object from a json object that actually owns its “_id” property (even set to “null”), insert fails with no error.
Example:
var json = JSON.parse(req.body.time);
var time = new Time(json);
assuming that json._id is defined, no matter it's declared as a new "Time", when you try to insert with:
time.save(function (error) {
if (error) { res.send({'error' : error}); }
res.send(time);
});
error variabile is null but item was never inserted.
In this case I solved by deleting "_id" property before populating mongoose object so final code as follows:
var json = JSON.parse(req.body.time);
delete json._id;
var time = new Time(json);
time.save(function (error) {
if (error) { res.send({'error' : error}); }
res.send(time);
});
Regards
Angelo
Not directly related to the scenario described in the post, but I was getting the same error.
The issue was that I was not calling next(); at the end of the pre('save') function on the model definition.
For example:
cartSchema.pre('save', function(next) {
const currentDate = new Date();
this.modified = currentDate;
if (this.isNew) {
this.created = currentDate;
this.cartid = uuidv4();
}
next(); // this was missing :'(
});
I had a situation where the save callback was getting called, but the document wasn't changing. I haven't yet tracked down the root cause (some sort of validation thing probably) but the problem had something to do with one of the changes I made. So I just tried the changes one by one until I found the culprit.
(Feel free to edit this answer if you figure out more of this phenomenon)