In my node.js express application I am retrieving a user from my database
const newUser = await User.create({
username,
password,
email,
avatar,
})
but before sending the response with the user object I want to remove the password.
delete newUser.password;
return res.status(200).json({ token, user: newUser });
but in my response the password is returned.
console.log(JSON.stringify(newUser))
returns:
{"_id":"11111111","username":"dylan","email":"dylan#email.com","admin":true,"password":"******"}
query return value is document not javascript object
Documents have a toObject method which converts the mongoose document into a plain JavaScript object.
first convert it to object and then use delete on each property you want
also with mongoose it can done more properly and automatically
User.methods.toJSON = function () {
const user = this;
const userObj = user.toObject();
delete userObj.password;
return userObj;
};
every time you send this document as response it convert to JSON and every time that JSON.strigify() is call on a document it call this toJSON() method
Maybe you can also do
delete newUser._doc.password
Related
This question already has answers here:
How to store objects in HTML5 localStorage/sessionStorage
(24 answers)
Closed 11 months ago.
I am trying to login to my user account which is saved on database and attach a token to that username with 'jwt-token'.
router.post('/users/login', (req, res) => {
User.authenticate()(req.body.username, req.body.password, (err, user) => {
if (err) { console.log(err) }
res.json(user ? jwt.sign({ id: user._id }, process.env.SECRET) : null)
})
})
However when i login to the account, the token is being saved, as [Object][Object] in the local storage via this function here,
// when a user clicks login
const handleLogin = (event) => {
event.preventDefault();
axios.post('/api/users/login', {
username: userState.username,
password: userState.password
}).then(token => {
console.log(token)
setLoginState(true)
localStorage.setItem('username', userState.username)
localStorage.setItem('token', token)
}).catch(err => { console.log(err) })
What is the reason the token is saving as an object? is it not properly being created by my route? or am I not calling it correctly in my .then call? any insight would be appreciated. Still trying to learn as much as i can on backend work and seem to hit problems at every step.
We have to stringify while storing objects in storage and parse the stored objects while retrieving.
// Put the object into storage
localStorage.setItem('username', JSON.stringify(username));
// Retrieve the object from storage
var retrievedUsername= localStorage.getItem('username');
console.log('retrievedUsername: ', JSON.parse(retrievedUsername));
localStorage.setItem() saves information as Strings which is why you see "[Object][Object]" being saved since that is what it is receiving.
So you need to transform your object to a String before you save it.
You can achieve this by using the JSON.stringify() function.
Note: you will have to transform the String back to an object when you need to get it.
You can achieve this by using the JSON.parse()
Example:
localStorage.setItem('username', JSON.stringify(userState.username))
localStorage.setItem('token', JSON.stringify(token))
JSON.parse(localStorage.getItem('username'))
JSON.parse(localStorage.getItem('token'))
axios promise returns response object which has a data attribute. To access token you should call
res.data
and store it like so
localStorage.setItem('token',res.data)
Below code is my fetch method in my separate register.js. This is my newly created js file, so I can create my front end. At the moment I'm just trying to console.log the ending result for this fetch, but can't get the output since I'm getting an error when I try to POST this.
error in browser console:
"Uncaught (in promise) SyntaxError: Unexpected token S in JSON at position 0"
fetch(`${rootUrl}api/users/register`,{
method:"POST",
headers:{
"Content-Type": "application/json"
},
body:JSON.stringify({
firstName: firstName,
lastName: lastName,
mobileNo: mobileNo,
email: email,
password: password
})
})
.then(result=>result.json())
.then(result =>{
console.log(result);
})
In userRouter.js, this is the route I'm fetching in register.js above:
router.post('/register', (req, res)=>{
userController.register(req.body).then(result => res.send(result))})
And the route leads to this controller in Usercontroller.js:
module.exports.register = (reqBody)=>{
//check if email already exists before registering new user
return User.find({email: reqBody.email}).then((result, error) =>{
if(result.length != 0){
return "EMAIL EXISTS!";
}else{
let newUser = new User({
firstName: reqBody.firstName,
lastName: reqBody.lastName,
email:reqBody.email,
password: bcrypt.hashSync(reqBody.password, 10),
mobileNo: reqBody.mobileNo
})
return newUser.save().then((result, error)=>{
if (error){
return error;
}else{
return "SUCCESFULLY REGISTERED NEW USER";
}
})
}
})}
As you can see, this is a registration form. Everything works fine in the backend, using postman to enter values. All my condition prompts are being returned(emails exist, successful registration).
But when I tried creating a frontend for it, I can't get my defined prompts.Like when I deliberately input a duplicate email, I can't get the message "Email exists" that I used to get when using only postman or just backend API functionality.
I feel like something is very wrong with what I'm trying to do. I'm having trouble creating a frontend for my API which I'm not used at the moment.
You are returning a non JSON response, so you can't use res.json(). You are simply sending a text response. So use res.text()
fetch('/your-endpoint').then((res)=>{
return res.text();
}).then((text)=>{
console.log(text)
})
There are some hints to be pointed out.
Check the rootUrl since after that there's no foreslash.
You're sending back the Text Style. use this instead to have the result json format.
res.status(200).json({result})
Try not to use Synchronous Functionalities on the back side. You
should give it a wide berth, or rather, use bcrypt.hash() mixed
with Async Function to remove the CallBack Function until it gets
done. What's more, so as to check the previous function's error to
get it on the front side using Fetch / Axios. use Try/Catch method.
I'd use axios [ axios.request({}) | axios.post(..)] if I were in
your shoes.
So I wanna clear it in first that I am a beginner in mongoose. So I wanted a help regarding saving arrays in the database. I want to relate this to Discord. I was building a bot where I want to store the ids of the channels to make the bot respond on them only. Earlier I was using Enmap, but transferred to mongoose for ease. So I don't know how to store arrays then push another string inside that array. Please help me out in this situation 😥
It's just so easy, after creating your model aka schema, you just set the type to array
example:
const mongoose = require('mongoose')
const schema = mongoose.Schema({
GuildId: {
type: String
required: true
},
ChannelIds: {
type: Array,
default: []
}
})
module.exports = mongoose.model("the_model_name", schema)
Alright now in your command you will need to get the data from the db
example:
// first you will need to define your schema
const schema = require('schema path')
// now we will define data and we will use try catch to not get any errors
let data;
try {
// Put here the guild id such as the message.guild.id, or anything that is unique for that data
data = await schema.findOne({ GuildId: ## })
// if there is no data we want to create a schema for it
if(!data) {
data = await schema.create({ GuildId: ## })
}
} catch(e) {
// if there is any error log it
console.log(e)
}
Now after we got the data we just push the channel id, to add it you just need to push it.
example
data.ChannelIds.push(/*the channel id or whatever you want to push*/)
last but not least just save the data
example
await data.save()
I wrote this code to check if an email already exists in the database:
async store (req,res) {
const email = req.body.email;
let user = await User.findOne ({ email: email });
if (user) {
console.log('Already exist.')
};
(...)
}
But it's not working: I can store the info in the User collection but it's email is not verified.
I'm using Mongoose.
What I'm doing wrong?
You need to use exec() at the end to actually run the query:
let user = await User.findOne({ email: email }).exec();
Also, since you're using await, make sure the containing function is marked async.
I am limited in the information I can give you because you just say "It's not working". That doesn't tell me anything. Do you run it and nothing happens? Does it give you an error? People on this site don't like to hear the words: "it's not working".
You haven't described your use case, but if you're looking to avoid email collisions, using mongoose, when you define the object's schema, you can use the unique: true option. It will then reject any new or updated User that submits an already stored email.
I'm using the combo Express (Node.js) and Mongoose to make a REST API. I'm trying to make the login using a JWT token but I've got a problem. When I execute the following code
const mongoose = require('mongoose');
const User = mongoose.model('User');
// other code
_api.post('/login', function (req, res) {
const data = req.body;
// some data control
User.findOne({ username: data.username}, function(err, doc) {
if (hash(password) == doc.password) { // password check
myToken = generateToken(); // generating the token
doc.jwtToken = myToken; // including the generated token to the response
res.status(200).json(doc); // return the final JSON to client
}
}
}
the final JSON returned by the API doesn't have the field "jwtToken":"mygeneratedtoken" and this is strange. I included other times new fields inside a JSON with the same syntax and it worked. I tried to use a tmp variable to which I assigned the doc content (that is a javascript object) and then I added the jwtToken filed and return the tmp variable. But nothing.
Can someone explain me if there is something wrong with my code or if there is something that I need to know?
Documents returned by mongoose are immutable, and thus assignment to doc.jwtToken does not modify the object. You can either use the lean method to modify the query, or toObject to convert the document to a regular javascript object. Try:
var docObject = doc.toObject();
docObject.jwtToken = myToken;
res.status(200).json(docObject);