Mongoose collection.update does not update the document - javascript

I am having an issue using Mongoose's update function. Basically the document I am trying to modify is not getting updated.
Here is the code:
const user = 'Joe Bloggs'
const salt = await bcrypt.genSalt()
const pwStr = 'simplepassword'
const hashedPassword = await bcrypt.hash(pwStr, salt)
User.update({user_name: user }, { $set: { password: hashedPassword }}, function(err, doc) {
if (err) console.log('Error ', err);
console.log('Updated Doc -> ', doc); // returns un-updated doc
});
As you can see there is not much to it. The only thing I thought could be causing an issue was the bcrypt functions, but they seem to be working and hashedPassword logs out fine.
The callback logs the document, but it is not updated and when I check it in the Mongo shell it is indeed not updated.
I previously tried findOneAndUpdate but it appears that has been deprecated.
So, I tried findOne, but this also failed to update the document. Here is the basic code which uses save on the found user instead.
User.findOne({user_name: user}).then(async function(user) {
user.password = 'easypassword';
await user.save();
}
});
I tried using update in the shell using the same { $set: {...}} syntax and it works.
If anyone can tell me why this operation isn't working when I try to do it using the Mongoose functions I'd much appreciate it. Thanks in advance!
EDIT
I have tried the suggested code below:
const res = await User.updateOne([filter], [query]);
This returns the following when res is logged out:
{ acknowledged: false }
This appears in MongoDB documentation to relate to a "write concern" setting, but I have no idea where to go with it from there.

update is what is actually deprecated.
findOneAndUpdate, like other mongoose update methods, it returns the un-updated object by default. Setting the option new to true will return the updated doc.
Another option would updateOne;
User.findOneAndUpdate(
{ user_name: user },
{ $set: { password: hashedPassword } },
{ new: true },
function (err, doc) {
if (err) console.log("Error ", err);
console.log("Updated Doc -> ", doc);
}
);

Related

saving documents to mongoDB preventing duplicates

I'm trying to save multiple documents in mongodb using mongoose; and I'm also willing to prevent duplicates. my function looks sth like this:
const Stock = require('./models/stock')
let _symbol = 'symb'
const writeToDB = async (dataObj) => {
try {
let stock = await Stock.find({symbol : _symbol } , function (err) {
if(err) return null
})
if (!stock) {
stock = new Stock({
dataObj
})
await stock.save()
console.log(`${symbol} is successfully saved to database`)
} else {
stock = await Stock.updateMany(
dataObj, function (err) {
if (err) {
console.log(err)
} else {
console.log(`${symbol} successfully added`)
}
})
}
} catch (error) {
console.log(error)
}
}
but I keep getting timeout error. can someone pls inform me what's wrong.
update
with a well handled connection approach findOneAndUpdate()works fine
Using the upsert option, in findOneAndUpdate(). An upsert behaves like a normal findOneAndUpdate() if it finds a document that matches filter. But, if no document matches filter, MongoDB will insert one by combining filter and update as shown below
var query = {symbol : _symbol };
try{
let result = await Stock.findOneAndUpdate(query, dataObj, {upsert: true})
}
catch(err){
console.log();
}
if you have a big collection, for increase speed findOneAndUpdate(), you should indexed symbol field.
when you use async await, it's better don't use callback and use try catch
I think the best, simply and easy way to prevent duplicate values is use unique value in the schema.
So your Stock schema has to have something similar to this:
symbol:{
type: String, // or whatever
unique: true
}
If you try to insert two object with same value, mongoose will trhow an error like:
MongoError: E11000 duplicate key error dup key: { : "repeatedSymbol" }
Also you can check the documentation.

Trying to use bcrypt,compare and returns Promise { <pending>}

I am trying to create a login api by using aws lambda, mongoose, and bcryptjs.
My lambda handler uses async and I am just trying to compare the user typed password with already hashed password that is in the database by using the bcrypt.compare() function in the bcryptjs module. However, my code keeps giving me Promise { } so I have tried a bunch of ways to fix this but still have an issue. I am new to using async so I might be doing totally wrong so please do not be harsh on me :)
I am getting the user account data with the encrypted password from MongoDB atlas by using the below code and it works perfectly.
let user = await User.findOne(query).select('_id name email password');
I also have a mongoose method that I have created in a user.js file just like below.
UserSchema.methods.comparePassword = function(password) {
return bcrypt.compare(password, this.password);
};
so the above method gets called and prints the result with console.log with the following code.
let passwordValid = user.comparePassword(parameters.password);
console.log('Password is validated', passwordValid);
and it gives me
INFO Password is validated Promise { <pending> }
in the lambda console.
I have done many searches so I tried using await before comparePassword like below and still not working.
let passwordValid = await user.comparePassword(parameters.password);
I have also tried resolving the returned promise by using then() like below
let passwordValid = user.comparePassword(parameters.password);
passwordValid.then(function(err, result) {
callback(null, {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({
"success": false,
"content": result
})
});
});
However, this still does not work as I want. Only respond I receive is
{
"message": "Internal server error"
}
Have you seen this https://www.npmjs.com/package/bcrypt?
In this line, await is neede:
return bcrypt.compare(password, this.password);
As the above link suggests:
async function checkUser(username, password) {
//... fetch user from a db etc.
const match = await bcrypt.compare(password, user.passwordHash);
if(match) {
//login
}
//...
}

MongoDB issue in query returning value from user

I am using MongoDB with Nodejs and I am trying to find the usertype value of a specific user so I've got this:
var myQuery= { username: req.body.username }, { "usertype": 1 };
dbo.collection("usercollection").find(myQuery, function(err, obj) { ...
What I need returned is the value of usertype from that specific user but it keeps saying I have a syntax error with : expected.
How can I fix this?
You have a syntax error since you're trying to define query and projection for find method in one line, try:
var myQuery= { username: req.body.username };
var options = { projection: { usertype: 1 } };
var cursor = dbo.collection("usercollection").find(myQuery, options)
I recommends to first perform the find operation to get the cursor and after it extract data from the cursor like below,
var myQuery= { username: req.body.username };
dbo.collection("usercollection").find(myQuery, { projection: { usertype: 1} }).toArray(function(err, result) {
if (err) throw err;
console.log(result);
});
In your case, the above code will work fine.

Find one element, use data, then delete it

In my node.js application I'm currently implementing a "Remember Me" functionality. Everything works quite well so far, but I have a problem with mongoose. What I want to do: I have a model named Token with this schema:
var TokenSchema = mongoose.Schema({
token: { type: String },
uid: { type: Schema.Types.ObjectId, ref: 'User' }
});
This is simply a little collection that maps cookie tokens to a UserId. Then I have this function here:
function consumeRememberMeToken(token, fn) {
Token
.findOne({ 'token': token }, (err, result) => {
return (result===null)?fn(null, null):fn(null, result.uid);
})
.remove();
}
What it should do, is this: find the uid for a given token string and return it (if there is a result). But this function should also delete the entry right after returning the uid.
At the moment, the uid from the found token result gets returned properly, but it (the result Token) does not get deleted from the collection with the above code. I don't understand how to remove it right after getting it and using the retrieved uid. I'm completely new to functional programming and I don't understand how and where to delete the token.
You can try db.collection.findOneAndDelete It deletes the document and returns the deleted data, quite the reverse of what you are saying but basically serves your purpose. here are the details.
Also here is the mongoose representation of the same.
Token.findOne({ 'token': token }, (err, result) => {
if(err || !result) return fn(err || "error", null);
else{
var uid = result.uid;
result.remove(function(){
return fn(null, uid);
});
}
})

MongoDB - Save vs Update for specific fields in document

Using the MEAN stack, I'm attempting to have an admin account update another user's information, in this case, their title/role on the site. The problem I have is that the only function available when editing a user is the save() function. It might be that I can utilize the update function, and if that is the case please let me know, but it doesn't look possible:
The problem arises that when the user is saved, it creates a new document, and overwrites the user's password and salt to some value. I'd like to be able to call an "update" function that will only update the one field, but I can't figure out how to. Is there a way to do this with the save function?
Relevant Code:
exports.updateUserRoles = function(req, res) {
var currUser = req.body;
User.findById(currUser._id, function(err, user) {
//user.roles = currUser.roles;
user.save( { _id : '56467b28ba57d8d890242cfa', roles : 'admin' } );
//THE BELOW WAS A PREVIOUS ATTEMPT
/*user.save( function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(user);
console.log('test2');
}
});*/
});
};
Trying something else that seems very close, but still not quite there yet.
Here's what I'm running:
exports.updateUserRoles = function(req, res) {
var currUser = req.body;
User.findById(currUser._id, function(err, user) {
//user.roles = currUser.roles;
//user.roles.set(0, 'admin');
console.log('test');
user.update(
{ _id: '56467b28ba57d8d890242cfa' },
{
$set: {
roles: 'admin',
},
}
);
console.log('test2');
});
};
Upon hitting the user.update line, we have the user in the local variables, seen:
user.update goes into this Document.prototype.update function, seen:
The args look to be building right, which _id we are targeting and what the action is, seen:
But then after running, nothing seems to change. I'm very much stumped.
For updates various fields in mongodb you can use update with different atomic operators, like $set, $unset, $push etc.
Example:
var updateUserRoles = function(db, callback) {
db.collection('users').updateOne(
{ "_id", : "user_id", },
{ $set: { "password": "new_password" } },
function(err, results) {
console.log(results);
callback();
}
);
};

Categories

Resources