Stuck on NodeJS mongoDB find() Query - node.js

I am unable to write the correct query.
I am trying to check if the user already exists in the database and it will respond in Login Successfully Response.
This code is in working position problem lies in Query.
I hope somebody will help
function login() {
app.post("/login/", async(req, res) => {
const query = new Model({
email: req.body.email,
password: req.body.password,
});
const cursor = Model.find(query); // (*Here's the problem*)
console.log(cursor);
if (query === cursor) {**strong text**
console.log(query);
res.send("login successfully");
} else {
console.log(query);
res.send("user does not exist ");
}
});
}
login();
// Model and Schema
const LoginSchema = new mongoose.Schema({
email: { type: String, required: true },
password: { type: String, required: true },
});
const Model = mongoose.model("login_details", LoginSchema);
// Registeration Phase
function registration() {
app.post("/register/", async(req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password,
});
const result = await model.save();
console.log(result);
res.send(model);
});
}
// Headers
const express = require("express");
const app = express();
const mongoose = require("mongoose");
app.use(express.json());
app.use(express.urlencoded({ extend: true }));
//

Issues with your code
1- You don't need to use new Model({}) to query
2- You're using .find() which returns an array, use findOne() instead
3- You're attempting to check if a mongoose model (with _id) equals a query without the _id which won't work
4- Use return at the end of your function (won't affect the functionality here but just as good practice not to encounter errors like cannot set headers after they're sent)
possible solution
function login() {
app.post("/login/", async (req, res) => {
const cursor = await Model.findOne({
email: req.body.email,
password: req.body.password,
});
console.log(cursor);
if (cursor) {
console.log(cursor);
return res.send("login successfully");
} else {
return res.send("user does not exist ");
}
});
}

You are using Mongoose in the wrong way. Try this.
const result = await Model.find({
email: req.body.email,
password: req.body.password,
});

Related

Router doesn't get response from database functions

when running the app and testing the /signup route the data gets written to the db and i can console.log it from the database/models.js file, but in the routes/index.js file it returns "Something went wrong." and postman shows nothing, not even an empty array or object.
routes/index.js
var express = require('express');
var router = express.Router();
const database = require('../database/models');
router.post('/signup', function(req, res, next) {
if (!req.body.email || !isValidEmail(req.body.email))
res.status(400).send('Email invalid.');
else if (!req.body.username || !isValidCredential(req.body.username) || !req.body.password || !isValidCredential(req.body.password))
res.status(400).send('Username/password invalid.');
else {
const result = database.createUser(req.body.email, req.body.username, req.body.password);
if (result)
res.status(200).send(result);
else
res.send('Something went wrong.');
}
});
function isValidEmail (email) {
if (email.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"))
return true;
else
return false;
}
function isValidCredential (credential) {
if (credential.length < 6)
return false;
else if (credential.match(/^[a-z0-9]+$/i))
return true;
else
return false;
}
module.exports = router;
database/models.js
const tools = require('./tools');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: String,
username: String,
hashedPassword: String,
salt: String,
accessToken: { type: String, default: "" }
});
const User = mongoose.model('User', userSchema);
function createUser(email, username, password) {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
newUser.save(function (error, result) {
if (error)
return handleError(error);
return { email: result.email, username: result.username };
});
}
module.exports.createUser = createUser;
In your code you are not returning anything when calling the createUser function. Here a couple of considerations:
// index.js
const result = database.createUser(req.body.email, req.body.username, req.body.password);
since the createUser is an operation performed on a database, it will be probably asynchronous, and therefore also its result. I suggest the usage of async/await to be sure of the returned result. Also, you need to change the code of your models.js file to return a Promise and await for it.
function createUser(email, username, password) {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
return new Promise((resolve, reject)=> {
newUser.save(function (error, result) {
if (error) reject(error);
resolve({ email: result.email, username: result.username });
});
});
}
and than you will have to await for your result. You can do it in the following way:
// index.js
// Add async here
router.post('/signup', async function(req, res, next) {
// ...other code
// Add await here
const result = await database.createUser(req.body.email, req.body.username, req.body.password);
I figured it out.
in routes/index.js use async/await like this:
router.post('/signup', async function(req, res, next) {
try {
if (!req.body.email || !isValidEmail(req.body.email))
res.status(400).send('Email invalid.');
else if (!req.body.username || !isValidCredential(req.body.username) || !req.body.password || !isValidCredential(req.body.password))
res.status(400).send('Username/password invalid.');
else {
const result = await database.createUser(req.body.email, req.body.username, req.body.password);
if (result)
res.status(200).send(result);
else
res.status(403).send(result);
}
} catch (error) { return error; }
});
and in database/models.js use async/await as well, but also rewrite mongoose methods into ones without callbacks, with returns into variables, like this:
async function createUser(email, username, password) {
try {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
const result = await newUser.save();
return { email: result.email, username: result.username };
} catch (error) { console.log (error); return error; }
}

How to check if username already exist in database collection MongoDB

I'm making post request on registration,But I want error to pop up if username is already taken.
Any suggestions?
Here is my post route:
app.post('/addUser', (req,res) => {
const addUser = new User({username: req.body.username, password: req.body.password})
addUser.save().then(result => res.status(200).json(result)).catch((err) => console.log(err))
})
Alternate method, depending on the error style you want.
const users = new mongoose.Schema(
{
username: {type: String, unique: 'That username is already taken'}
},
{ timestamps: true }
)
Now mongo will index usernames and check it before the insertion. An error will be thrown if it's not unique.
You can use findOne method of mongoose
app.post('/addUser', async (req,res) => {
//validation
var { username, password } = req.body;
//checking username exists
const existUsername = await User.findOne({ username: req.body.username});
if (existUsername) {
console.log('username taken');
}
});

why method declared in Mongoose schema wasnt working

So, here's my user schema where i declared hello method onto the Userschema which im using to test
//user.model.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
password: { type: String, required: true }
});
UserSchema.methods.hello = () => {
console.log("hello from method");
};
const User = mongoose.model("User", UserSchema);
module.exports = User;
here's routes file
//authroutes.js
const router = require("express").Router();
let User = require("../models/user.model");
router.route("/").get((req, res) => {
res.send("auth route");
});
router.route("/signup").post((req, res) => {
const username = req.body.username;
const password = req.body.password;
const newUser = new User({
username,
password
});
newUser
.save()
.then(() => res.json(`${username} added`))
.catch(err => console.log(err));
});
router.route("/login").post(async (req, res) => {
await User.find({ username: req.body.username }, function(err, user) {
if (err) throw err;
//this doesnt work
user.hello();
res.end();
});
});
module.exports = router;
in the login route im calling hello function to test but that doesnt work and throws this error
TypeError: user.hello is not a function
You need to use User.findOne instead of User.find, because find returns an array, but what we need is an instance of the model.
Also Instance methods shouldn't be declared using ES6 arrow functions.
Arrow functions explicitly prevent binding this, so your method will not have access to the document and it will not work.
So you had better to update method like this:
UserSchema.methods.hello = function() {
console.log("hello from method");
};

mongoose Model.create function returns undefined

The above query returns a 200 when I try to create a User, but whenever I log into MongoDB there is no collections created. Can anyone help ?
//user model
const userSchema = mongoose.Schema({
name: {
type : String,
required : true,
trim : true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
validate: value => {
if(!validator.isEmail(value)){
throw new Error({error : 'Invalid email address'})
}
}
},
password: {
type: String,
required: true,
minLength: 5
},
// a user can have multiple jobs
jobs : [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Job'
}],
tokens: [{
token: {
type: String,
required: true
}
}]
})
const User = mongoose.model('User', userSchema)
module.exports = User
// user functions written
createUser(name, email, password){
return User.create({name: name, email: email, password : password}, (err, docs) => {
if(err){
throw err.message;
}
});
}
//routes.js
// user create
router.post('/users', async(req, res) => {
try{
const {name, email, password } = req.body
const user = userManager.createUser(name, email, password); [1]
res.status(200).json(user)
}
catch(error) {
res.status(400).send({error : error.message})
}
})
The line[1] returns undefined. Why ?
note : all module requirements are fulfilled
After you create the schema you need to create a Model FROM that schema.
Example from MDN:
// Define schema
var Schema = mongoose.Schema;
var SomeModelSchema = new Schema({
a_string: String,
a_date: Date
});
// Compile model from schema
var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
Now after you create the model you can use SomeModel.create
EDIT:
line[1] will always return undefined because you are using callbacks and only way to get value out of callback is either push another callback(I would really discourage that). But best way is to use Promises now mongoose by default supports `Promises. So, basically for promises it will be,
// user functions written
async function createUser(name, email, password){
try {
return await User.create({ name: name, email: email, password: password });
} catch (err) {
throw err.message;
}
}
In the router adda await:
const user = await userManager.createUser(name, email, password);
The problem is you call an asynchronous function synchronously. It returned undefined because the function hasn't been resolved yet.
A solution could be to use promises or async/await.
Example:
async createUser(name, email, password) {
const createdUser = await User.create({name,email,password});
return creaatedUser;
}
Something I ran into was you need to pass in an empty object if your not setting any fields - i.e.
Good: Model.create({})
Bad: Model.create()

Returning values after save in Mongoose

I'd need some help on returning values after saving a new entry to my db using mongoose.
This is how my controller looks:
var userModel = require('../models/users');
module.exports = {
findAll: function(req, res) {
userModel.user.findAll(function(err, users) {
return res.json(users);
});
},
findId: function(req, res) {
var id;
id = req.params.id;
userModel.user.findId(id, function(err, user) {
return res.json(user);
});
},
addUser: function(req, res) {
newUser = new userModel.user;
newUser.username = req.body.username;
newUser.password = req.body.password;
newUser.addUser(function(err, user) {
return res.json(user);
});
}
};
And here's my users.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
module.exports = {
findAll: UserSchema.statics.findAll = function(cb) {
return this.find(cb);
},
findId: UserSchema.statics.findId = function(id, cb) {
return this.find({
_id: id
}, cb);
},
addUser: UserSchema.methods.addUser = function(cb) {
return this.save(cb);
}
};
This all works ok, but it only returns me the newly added user with addUser. I would like to get all the entries, including the newsly added one, as a return value. Just like using "findAll". How would be able to do this?
Yes, like bernhardw said there doesn't seem to be a way to return anything but the added document with save().
I followed his advice and called findAll() inside addUser() and it all works perfect now -> I can return all my users after saving a new new one. Thanks.

Resources