mongodb: cannot set property as null though its working in shell - node.js

I am trying to build OTP generation and verification module with
Nodejs,mongodb,Nexmo
BUT IT IS WORKING IN SHELL
here is my code
PHONE SHCHEMA
const phoneSchema = new Schema({
mobileNo:{type: String},
count:{type:String},
verified:{
type:String,
defaultValue:0
},
lastFive:{
type:Date,
default: Date.now
},
},{ timestamps: true})
const Phone = mongoose.model('Phone', phoneSchema)
module.exports = Phone
OTP SCHEMA
const otpSchema = new Schema({
otp:{
type:Number,
unique: true
},
mobileNo:{ type:String,}
},{ timestamps: true})
const Otp = mongoose.model('Otp', otpSchema)
module.exports = Otp
LOGIN CONTROLLER
const nexmo = new Nexmo({
apiKey: '#######',
apiSecret: '########'
})
exports.getOtp = async (req,res,next)=>{
try{
const {mobileNo} = req.body
let phone = await MobileNo.findOne({mobileNo})
if(!phone){
const error = new Error('Number you have entered is not registered Please contact dealer')
throw error
}
else{
Otp.findOneAndDelete({mobileNo})
const dates= phone.lastFive.toString().split(';')
if(dates.length>=5){
const msec=(Date.now()- parseInt(dates[0]) )
const minute=Math.floor(msec / 1000 / 60)
if(minute<=5){
return res.json({
err:'5 minute 5 Otp limit. Wait'
})
}else{
phone.count++;
phone.lastFive=Date.now();
}}
else{
phone.count++;
phone.lastFive=`${phone.lastFive} ${Date.now()}`
}}
let otp,randomOtp;
while(true){
randomOtp = Math.floor( Math.random() * (10000 - 1000) + 1000)
otp = await Otp.findOne({otp} )
if(!otp){
otp = new Otp({
otp:randomOtp,
mobileNo
})
setTimeout(()=>{
otp.delete();
},1000*60*5);
break}}
const from = 'Nexmo'
const to = mobileNo
const text = `Verification code :- ${randomOtp}`
nexmo.message.sendSms(from, to, text,async (err, response) => {
if (err) {
next(err);
} else {
await phone.save()
await otp.save()
res.json({
msg:'OTP is send Successfuly',
success:true
})
}
})}
catch(err){
next(err)}}
VERIFYING OTP
exports.verifyOtp= async(req,res,next)=>{
const {otp,mobileNo}= req.body;
try{
const checkOtp = await Otp.findOne({otp,mobileNo});
if(!checkOtp){
throw new Error('Invalid Otp')
}
else
{
const findPhone = await MobileNo.findOne({ mobileNo:checkOtp.mobileNo,otp} )
findPhone.verified=1;
findPhone.save();
checkOtp.delete();
return res.json({
msg:'OTP is verified',
success:true
})}}
catch(err){
next(err)}}
** ROUTE **
const loginController = require('../controllers/loginController')
router.post('/getotp', loginController.getOtp)
router.post('/verifyotp', loginController.verifyOtp)
module.exports = router
** ERROR**
findPhone null TypeError: Cannot set property 'verified' of null
at exports.verifyOtp (######\backend\src\controllers\loginController.js:164:31)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
<

Related

POST going directly to the catch error and not saving data using mongoose, MongoDB, NodeJS, and Express

I already tried some possible solutions and even created and wrote the code again but I am still getting errors. I have created a diminute version of my whole code which connects to the database using Mongoose but after the Schema is created and I import the model in places-controllers my data that I write in POSTMAN goes directly to:
FYI: In this case I want POST request from createPlace to properly work.
Data entry: URL: http://localhost:5000/api/places/
{
"title": "Punta Arena Stfdsfdsfsdfop",
"description": "One stop Stop. Does not have tr12affic lights.",
"busrespect": "12ysdfdsfsfes",
"address": "Avenida Solunna",
"creator": "52peru soiflsdjf36"
}
OUTPUT:
{
"status": "error caught"
}
which is what I told the program to define if the try did not work.
IN app.js I have the following code:
const express= require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const placesRoutes = require("./routes/places-routes");
const HttpError = require ("./models/http-error");
const app = express();
app.use(bodyParser.json());
app.use('/api/places', placesRoutes);
app.use((req, res, next) => {
const error= new HttpError('Route not available. Try something different?', 404);
throw error;
});
app.use((error, req, res, next) =>{
if (res.headerSent) {
return next(error);
}
res.status(error.code || 500)
res.json({message: error.message || "An unknown error occured! Sorry" });
});
url = '<mongo_url>'
mongoose.connect(url, {useNewUrlParser: true}).then(()=>{
console.log("Connected to database")
app.listen(5000);
}).catch(erro => {
console.log(erro)
});
In places-routes.js I have the following code:
const express = require('express');
const {check} = require('express-validator')
const placesControllers=require('../controllers/places-controllers');
const router = express.Router();
router.get('/:pid', placesControllers.getPlaceById );
router.get('/user/:uid',placesControllers.getPlacesByCreatorId );
router.post('/' ,[
check('title')
.not()
.isEmpty(),
check('description').isLength({ min: 5 }),
check('address')
.not()
.isEmpty()
],
placesControllers.createPlace);
router.patch('/:pid', [
check('title')
.not()
.isEmpty(),
check('description').isLength({ min: 5 })
] , placesControllers.updatePlace );
router.delete('/:pid', placesControllers.deletePlace);
module.exports=router;
In places-controllers.js I have the following code:
const HttpError = require('../models/http-error');
const { validationResult } = require('express-validator');
//const getCoordsForAddress= require('../util/location');
const BusStop = require('../models/place');
let INITIAL_DATA = [
{
id: "p1",
title: "Samoa Stop",
description: "My first bus stop in Lima",
//location: {
// lat: 40.1382,
// lng:-23.23
// },
address: "Av. La Molina interseccion con calle Samoa",
busrespect: "yes",
creator: "u1"
}
];
const getPlaceById = (req, res, next) => {
const placeId = req.params.pid // Accessing the p1 in pid URL scrapping {pid:'p1'}
const place= INITIAL_DATA.find(p => { //find method goes over each element in the array, the argument p represents the element where find loop is
return p.id ===placeId
});
if (!place) {
const error= new HttpError('No bus stop found for the provided ID.', 404);
throw error;
}
res.json({place: place});
};
const getPlacesByCreatorId = (req, res, next)=> {
const userId = req.params.uid;
const places = INITIAL_DATA.filter(p=>{ //filter to retrieve multiple places, not only the first one
return p.creator ===userId;
});
if (!places || places.length===0) {
return next(
new HttpError('Could not find bus stops for the provide user id', 404)
);
}
res.json({places});
};
const createPlace = async (req, res,next) => {
const errors = validationResult(req);
if (!errors.isEmpty()){
return next(new HttpError ('Invalid bus stop please check your data', 422));
}
//const { title, description, busrespect, address, creator } = req.body; //erased location for now.
/* let place = new BusStop({
title: req.body.title,
description: req.body.description,
busrespect: req.body.busrespect,
address : req.body.address,
creator: req.body.creator
})
awaitplace.save()
.then(response=>{
res.json({
message : "Employee added sucessfully!"
})
})
.catch(err=>{
res.json({
message : "An error has occured!"
})
})
} */
const { title, description, busrespect, address, creator } = req.body;
try {
await BusStop.create({
title:title,
description: description,
busrespect:busrespect,
address: address,
creator: creator
});
res.send({status: "ok"});
} catch(error) {
res.send({status:"error caught"});
}
};
const updatePlace = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()){
console.log(errors);
throw new HttpError ("Invalid inputs passed, please check your data ", 422);
};
const { title, description } = req.body;
const placeId = req.params.pid;
const updatedPlace = { ...INITIAL_DATA.find(p => p.id === placeId)};
const placeIndex = INITIAL_DATA.findIndex(p => p.id === placeId);
updatedPlace.title = title;
updatedPlace.description = description;
INITIAL_DATA[placeIndex] = updatedPlace;
res.status(200).json({place: updatedPlace});
};
const deletePlace = (req, res, next) => {
const placeId = req.params.pid;
if (!INITIAL_DATA.find(p=> p.id ===placesId))
throw new HttpError('Could not find a bus stop for that ID ')
INITIAL_DATA = INITIAL_DATA.filter(p=> p.id !== placeId)
res.status(200).json({message: 'Deleted Place'});
};
exports.getPlaceById= getPlaceById;
exports.getPlacesByCreatorId = getPlacesByCreatorId;
exports.createPlace = createPlace;
exports.updatePlace = updatePlace;
exports.deletePlace = deletePlace;
Inside models folder I have two files: http-error.js which has this code:
class HttpError extends Error {
constructor(message, errorCode) {
super (message);
this.code = errorCode;
}
}
module.exports = HttpError;
The other file inside is the schema which is place.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const placeSchema = new Schema({
title: {
type: String
},
description: {
type: String
},
address: {
type: String
},
busrespect: {
type: String
},
creator: {
type: String
}
},
)
const BusStop = mongoose.model('BusStop', placeSchema)
module.exports= BusStop
Summary: somewhere in the try catch part from createPlace something is going wrong since my data entry is always going to the error status I indicated in that part.

How to add data inside nested array in mongodb

I am using mongoose for database functionalities in my nodejs project.Below is my model.
Here is the POST request:
In MongoDb data is saving like this :
Here owers array is empty.
expense.js
const mongoose = require('mongoose');
const ExpenseSchema = new mongoose.Schema({
userid:{
type: String,
required: true
},
owers:[{
owerid:{
type: String
},
amt:{
type: Number
}
}],
name:{
type: String,
required: true
},
amount:{
type: Number,
require: true
}
});
const expense = mongoose.model('expense',ExpenseSchema);
module.exports = expense;
Whenever I am trying to insert something array is showing empty.Below is my code:
addExpense.js
const expense = require('../models/expense.js');
const addExpense = async (req,res) => {
const {name,amount,owerid,amt} = req.body;
console.log(name + " " + owerid);
const {userid} = req.params;
const expens = new expense({userid,name,amount});
try{
const data = await expens.save();
expens.owers.push({"owerid":owerid,"amt":amt});
res.send({"id":data._id});
}
catch(error){
res.send(error);
}
};
module.exports = {addExpense};
Someone let me know what I am doing wrong.
Try This
const {name,amount,owers} = req.body;
console.log(name + " " + owerid);
const {userid} = req.params;
const expens = new expense({userid,name,amount});
try{
const data = await expens.save();
//After you can push multiple data like that
JSON.parse(owers).map((value) => {
data.owers.push({
owerid: value.owerid,
amt: value.amt
})
})
data.save()
res.send({"id":data._id});
}
catch(error){
res.send(error);
}

HOW TO FIX Mongoose 5.11.8 model.find() ERROR Operation `thanks-leaderboards.find()` buffering timed out after 10000ms

How to solve model.find() function produces "buffering timed out after ... ms"? I'm using mongoose v 5.11.8, npm v6.14.8 and mongodb v3.6.3
Here's the code.
thanks-leaderboard.js
const thanksLeaderboardSchema = require('../../schemas/thanks-leaderboard-schema.js')
const thanksSchema = require('../../schemas/thanks-schema.js')
const fetchTopMembers = async (guildId) => {
let text = ''
const results = await thanksSchema
.find({
guildId,
})
.sort({
received: -1,
})
.limit(10)
for (let counter = 0; counter < results.length; ++counter) {
const { userId, received = 0 } = results[counter]
text += `#${counter + 1} <#${userId}> with ${received} thanks\n`
}
text += '\nThis is updated every minute'
return text
}
const updateLeaderboard = async (client) => {
const results = await thanksLeaderboardSchema.find({}).where('channelId')
for (const result of results) {
const { channelId, _id: guildId } = result
const guild = client.guilds.cache.get(guildId)
if (guild) {
const channel = guild.channels.cache.get(channelId)
if (channel) {
const messages = await channel.messages.fetch()
const firstMessage = messages.first()
const topMembers = await fetchTopMembers(guildId)
if (firstMessage) {
firstMessage.edit(topMembers)
} else {
channel.send(topMembers)
}
}
}
}
setTimeout(() => {
updateLeaderboard(client)
}, 1000 * 60)
}
module.exports = async (client) => {
updateLeaderboard(client)
}
set-leaderboard.js
const leaderBoardSchema = require('../../schemas/thanks-leaderboard-schema.js')
module.exports = {
commands: 'setleaderboard',
requiredRoles: ['Administrator'],
description: 'Erstelle ein Leaderboard für die vergebenen Danksagungen',
callback: async (message) => {
const { guild, channel} = message
const guildId = guild.id
const channelId = channel.id
await leaderBoardSchema.findOneAndUpdate({
_id: guildId,
channelId,
},
{
_id: guildId,
channelId,
},
{
upsert: true,
})
message.reply('Leaderboard wurde erstellt!').then((message) => {
message.delete({
timeout: 1000 * 5,
})
})
message.delete()
}
}
thanks-leaderboard-schema.js
const mongoose = require('mongoose')
const reqString = {
type: String,
required: true,
}
const thanksLeaderboardSchema = mongoose.Schema({
// Guild ID
_id: reqString,
channelId: reqString,
})
module.exports = mongoose.model('thanks-leaderboards', thanksLeaderboardSchema, 'thanks-leaderboards')
thanks-schema.js
const mongoose = require('mongoose')
const reqString = {
type: String,
required: true,
}
const thanksSchema = mongoose.Schema({
userId: reqString,
guildId: reqString,
received: {
type: Number,
default: 0,
},
lastGave: Date,
})
module.exports = mongoose.model(
'thanks',
thanksSchema,
'thanks'
)
I tried increasing the bufferTimeoutMS or disabling the bufferCommands but still it won't work. This Code is supposed to readout the database every 60 seconds but the timeout happens after 10 seconds... can't figure out how to fix this error. I've already tried to delete the node_modules folders for mongoose and mongodb and reinstall them via npm but that didn't work as I get this error again.

Mongoose transaction over separate databases

I am trying to create a transaction to create documents in two separate databases using Mongoose. I wrote this piece of code, it creates docs in the databases, but when if I throw an error in the code, the docs still appear in the db's. Can anybody help me figure out what I do wrong?
const mongodb = mongoose.createConnection(MONGODB_URL, mongoOptions);
const session = await mongodb.startSession();
session.startTransaction();
try {
let db = mongodb.useDb('superUs');
const OrgModel = db.model('Organization', Organization, 'Organizations');
const newOrg = OrgModel.create([org, { session }]);
db = mongodb.useDb('anotherDb');
const UtilRecModel = db.model('User', User, 'util');
const NewUtilRec = UtilRecModel
.create([{ username: 'user', password: 'pwd', isAdmin: false }, { session }]);
session.commitTransaction();
session.endSession();
} catch(err) {
session.abortTransaction();
console.log('err');
}
const dbName = `organization-${org.title}`;
let sessionSuper;
let sessionOrg;
try {
const dbSuper = mongodb.useDb('superUs');
const dbOrg = mongodb.useDb(dbName);
const OrgModel = dbSuper.model('Organization', Organization, 'Organizations');
const UtilRecModel = dbOrg.model('User', User, 'util');
sessionSuper = await dbSuper.startSession();
sessionOrg = await OrgModel.startSession();
sessionSuper.startTransaction();
sessionOrg.startTransaction();
await OrgModel.create([org], { session: sessionSuper });
await UtilRecModel.create([{ username: 'util', password: 'util', isAdmin: false }], { session: sessionOrg });
sessionSuper.commitTransaction();
sessionSuper.endSession();
sessionOrg.commitTransaction();
sessionOrg.endSession();
} catch(err) {
sessionSuper.abortTransaction();
sessionOrg.abortTransaction();
sessionSuper.endSession();
sessionOrg.endSession();
throw(err);
}

Mongoose validation fails for required fields even when I provide values for that fields

I have the following model:
/**
* #module optikos
*/
const mongoose = require('mongoose');
/**
* Define the schema of the main table(Document)
* Needs to be redefined to add user role here
*/
const dbUri = 'mongodb://localhost:27017/optikosmaindb';
mongoose.connect(dbUri,{ useNewUrlParser: true });
const optikosSchema = mongoose.Schema({
name: {
type: String
},
email: {
type: String,
required:[true,'Email is required']
},
password: {
type: String,
required:[true,'Password is required']
},
dbpath: {
type: String,
required:true
},
role:{
type:String,
lowercase:true,
enum:{
values:['admin','employee','shop owner'],
message:'`${VALUE} is not a valid role`'
},
default:'shop owner'
},
payment_status: {
/***
* Only show owners need to have a payment status
*/
required:this.role == 'shop owner',
type: String,
lowercase:true,
enum:{
values:['pending','paid'],
message:'`{VALUE} is not a valid payment status`'
},
default: 'pending' //will change to paid once a payment transaction is completed
},
payment_reset: {
required:this.role == 'shop owner',
type: Date,
default:Date.now
}
});
const Optikos = mongoose.model('optikos',optikosSchema);
module.exports = Optikos;
I have another file called index.js in which I require it like this to create some users for my database:
const admins = require('./admins');
const Optikos = require('../schemas/optikos');
const bcrypt = require('bcrypt');
async function setup() {
console.log('Setting app Optikos main database');
try {
let registeredAdmins = admins.map(async admin=>{
let {email,name,password} = admin;
let role = 'admin';
let saltRounds = 10;
password = await bcrypt.hash(password,saltRounds);
let dbpath = dbUri;
let user = new Optikos({
'name':name,
'email':email,
'password':password,
'role':role,
'dbpath':dbpath
});
return user;
});
let response = await Optikos.create(registeredAdmins);
console.log('Registered admins')
process.exit(0);
} catch (e) {
console.log('Error error error')
console.log(e)
process.exit(1)
}
}
setup();
The admins file is an array of objects containing a name,email and password fields.However after trying to run the indexfile I get the following: "{ ValidationError: optikos validation failed: dbpath: Path dbpath is required., password: Password is required, email: Email is required".However If I log all the variables that I am passing to "new Optikos()" I get the values that I expect.What is wrong?
I solved the required fields error by doing this:
let registeredAdmins = admins.map(async admin=>{
let {email,name,password} = admin;
let role = 'admin';
let saltRounds = 10;
password = await bcrypt.hash(password,saltRounds);
let dbpath = dbUri;
let user = new Optikos({
'name':name,
'email':email,
'password':password,
'role':role,
'dbpath':dbpath
});
return user;
});
Promise.all(registeredAdmins)
.then(async users=>{
console.log(users)
await Optikos.create(users);
console.log('Yeap')
}).catch(e=>{
console.log(e)
})
Since registeredAdmins is a list of promises I use Promise.all() to get the values of the resolved promises.Thanks #AbdullahDibas for the hint
It is usually due to the fact that async await doesn't work the expected way in the situations of looping often ( though another alternative for the same is for-await-in, but it is still not considered to be production safe, or a good practise by some of the eslint standards ) and so, you may wish to rephrase your code as :
const admins = require('./admins');
const Optikos = require('../schemas/optikos');
const bcrypt = require('bcrypt');
async function setup() {
console.log('Setting app Optikos main database');
const passwordPromises = [];
try {
admins.forEach(admin => {
let { password } = admin;
let saltRounds = 10;
passwordPromises.push(bcrypt.hash(password, saltRounds));
});
const passwords = await Promise.all(passwordPromises);
let registeredAdmins = admins.map((admin, index) => {
let { email, name } = admin;
let user = new Optikos({
'name': name,
'email': email,
// The below would work because Promise.all resolves them in
// the sequential order. Also, since there would be a one - to - one
// mapping in the indices of the admins and the password due to the above stated fact
// the following would work
'password': passwords[index],
'role': 'admin',
'dbpath': dbUri
});
return user;
});
let response = await Optikos.create(registeredAdmins);
console.log('Registered admins')
process.exit(0);
} catch (e) {
console.log('Error error error')
console.log(e)
process.exit(1)
}
}

Resources