Get data from MongoDB query ( in Auth0 rules) - javascript

I can´t get data from my mongoDb (it´s hosted in Mlab), always returns the same error: user does not exist.
It´s a very simple query but I don´t seem to be able to get it right. My user has an email and a role in the database, so I´m trying to query based on the email and get the role.
mongo('mongodb://user:pass#data.mlab.com:port/database',
function (db) {
console.log(user.email);
var users = db.collection('users');
var result = users.findOne({email: 'email#email.com'});
var role = result.role;
What am I missing?

mongoose.Promise = global.Promise; // Promise fix if you will use mongoose
mongoose
.connect(
"mongodb://user:pass#data.mlab.com:port/database",
{ useNewUrlParser: true, useMongoClient: true }
)
.then(db => {
let dbo = db.db("database");
let query = { email: "email#email.com" };
dbo
.collection("users")
.find(query)
.toArray(function(err, result) {
if (err) throw err;
// remember it returs array
// you can map this array
// like this -> result.map(user => console.log(user.role))
console.log(result);
db.close();
});
})
.catch(console.log);
try to use mongoose and make sure you use your own promises as described here

Try this:
mongo('mongodb://user:pass#data.mlab.com:port/database', function (db) {
var users = db.collection('users');
users.findOne({email: 'email#email.com'}, , function (err, user) {
if (err) return callback(err);
if (!user) return if (!user) return callback(new WrongUsernameOrPasswordError(email)
var role = result.role;
});
You can also look into the MongoDB login template used in Custom Database connections scripts: https://auth0.com/docs/connections/database/custom-db/templates/login#mongodb

Related

I am trying to use the mongodb client for js to validate if a db exists in the db before other actions. What would be the best way to use it?

Here is the code snippet I am using where sourceUri is the connection string, nsfrom is the db. How do I block the rest of the code until I get console.log (`Database "${nsFrom}" exists.`);
MongoClient(sourceUri, { useUnifiedTopology: true },function (err, sourceMongoClient){
const sourceAdminDb = sourceMongoClient.db(nsFrom);
sourceAdminDb.admin().listDatabases((err, result) => {
if (err) throw err;
console.log(result);
const sourceDbExists = result.databases.some(sourceAdminDb => sourceAdminDb.name === nsFrom);
if (sourceDbExists){
console.log (`Database "${nsFrom}" exists.`);
}
else{
console.log (`Database "${nsFrom}" doesn't exist.`);
}
})
})

Mongoose findOneAndUpdate doesn't find (or update) in Node

I'm trying to add user input (url's) to a database with Mongoose but also checking if the added data already exists. Instead it seems to be creating a new model every time.
This shows the res.json(input) on screen, not the test json
var mongo = require('mongodb');
var mongoose = require('mongoose');
var cors = require('cors');
// Basic Configuration
var port = process.env.PORT || 3000;
process.env.DB_URI="omg it's my secret url"
// Connect to DB.
mongoose.connect(process.env.DB_URI, { useNewUrlParser: true, useUnifiedTopology: true }).
catch(error => handleError(error));
mongoose.connection.on('error', err => {
console.log(err);
});
app.use(cors());
//First we create a schema and Model in MongoDB.
const urlSchema = new mongoose.Schema({
original_url: String,
short_url: Number
});
const urlModel = mongoose.model('urlModel', urlSchema);
app.post(/PATH, function(req, res, done) {
//Now we check if the input-url was actually valid.
if(!/(^https:\/\/)/.test(req.body.url)){
res.json({error: "Invalid url"});
}
//If it's valid we will start creating a model in the DB.
else {
var userUrl = req.body.url;
var urlNumber = 0;
var input = new urlModel({
original_url: userUrl
});
//Now we check if the url was already added to the database and return a new or updated item.
urlSchema.pre('save', function (next) {
var query = {'original_url': userUrl };
urlModel.findOneAndUpdate(query, userUrl, {upsert: true}, function(err, doc) {
if (err) return res.send(500, {error: err});
res.json({'test': 'test'});
});
});
res.json(input);
urlNumber++;
input.save(function(err, data) {
if (err) return console.log(err);
done(null, data);
});
};
});
As you can see I also have a problem updating the number that I want to attach to the url in the database, since I re-assign 0 to urlNumber at the beginning of the call. Must be because it's late but I can't seem to find a way to update that number correctly. I tried two variables and checking them against each other and an if(urlNumber > 0), but that's a problem I'm still solving. Seems so simple..
Anyway the question here is: why doesn't findOneAndUpdate seem to update? The returned res.json(input) shows a new '_id' every time, which tells me it does actually create new models every run.
Example returns
#1
{
_id: eksdjh3948wryeids293ren12;
original_url: "https://www.correct.com"
short_url: 0
}
#2
{
_id: eksdjh3948wryeids293ren13; // (<----- NEW NUMBER)
original_url: "https://www.correct.com"
short_url: 0
}
Your pre('save' function(next) {}) hook isn't calling next()
Turns out the .pre hook doesn't work with findOneAndUpdate! If I just remove that, the code now works as expected.

Unable to pass custom express-validator check

The purpose of the following code is to check whether an email already exists in MongoDB, using express-validator:
app.post('/registerPage',[check('email').custom((email) => {
// connect to database
let MongoClient = require('mongodb').MongoClient;
let url = 'mongodb://localhost';
MongoClient.connect(url, function(err, client) {
if (err) throw err;
let db = client.db('Mydatabase');
// search database
return db.collection('users').findOne({
email: email
}).then(user => {
if (user) {
console.log(user); // here console shows correct record in database
return Promise.reject('E-mail already in use');
}
// otherwise, it returns null
});
})
}).withMessage('Error Message Example')], (req, res) => {
// Handle the request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() })
}
});
When email already exists, console shows Promise.reject('E-mail already in use');.
The problem is when email does not exist, although it doesn't show Promise.reject, the code cannot process any further, validationResult(req) is not empty, so it still prints out the error message 'Error Message Example'. But there isn't any problem with non-custom validators which can successfully pass the checks.
I tried to add an else statement where !user, it doesn't work.
The question is how to pass the custom validation check, or why the array validationResult(req) is not empty even it should be? How do I make sure validationResult is empty after all checks were passed.
The issue is you are returning the promise in the callback of MongoClient.connect and not the validator function. Try using Promise wrapper like:
app.post('/registerPage',[check('email').custom((email) => {
return new Promise((resolve, reject) => {
// connect to database
let MongoClient = require('mongodb').MongoClient;
let url = 'mongodb://localhost';
MongoClient.connect(url, function(err, client) {
if (err) throw err;
let db = client.db('Mydatabase');
// search database
return db.collection('users').findOne({
email: email
}).then(user => {
if (user) {
console.log(user); // here console shows correct record in database
return reject('E-mail already in use');
}
return resolve();
});
})
});
}).withMessage('Error Message Example')], (req, res) => {
// Handle the request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() })
}
});
Hope this helps!

Append to array from mongodb query result and update database

I am developing an express webapp that has a friends list feature, the list is an array that is part of the user record in the database. What I am trying to do is to set up a route that adds the user from the route parameter to the logged in user's friends list array and updates the database.
My approach is to acquire the friends list document via collection.find() query (which works), modify it via javascript and update the database in a callback function.
The modifying part is what causes me problems, since the mongodb queries don't return json, but mongodb query objects. I don't know how to parse them. How can I get only the values to edit from that document?
router.get('/users/:specifiedUser/addfriend', function(req, res){
var currentUser = req.user.username;
var specifiedUser = req.params.specifiedUser;
var db = req.db;
var collection = db.get('usercollection');
var friendsList = [];
collection.find({ username : currentUser },{ friendsList : 1 }, function (err, result){
//TODO: convert result values to friendsList array, append specifiedUser to the array that is then updated in the callback
collection.update({username : currentUser },{friendsList : friendsList }, function (err) {
if (err) {
// return error if it fails
console.log(err.message);
return res.render('index', { error : err.message });
};
});
if (err) {
// return error if it fails
console.log(err.message);
return res.render('index', { error : err.message });
};
});
});

How to wait mongoose .exec function to be done?

I am some cofused by asychronous nodejs and mongoose. Simplily, I want to post an array of usernames and check, if a username is in database, then I put it in the valid array, otherwise, put it in the invalid array.
Here is my current code:
var User = require('../../db/models/user');
api.post('/userlist', function(req, res) {
var invalid = []; // usernames which can not be found in database
var valid = []; // usernames which can be found in database
(req.body.userlist).forEach(function(username) {
User
.findOne({username: username})
.exec(function(err, user) {
if (err) {
res.send(err);
return;
} else if (!user) {
invalid.push(username);
} else {
valid.push(req.params.item);
}
});
});
res.send({
Invalid: invalid,
Valid: valid
});
});
When I executed the above code, it outputs the intial empty array directly.
Invalid: [],
Valid: []
I know it is because nodejs first execute this res.send then execute function .exec(function(err, user), but i do not know how to get the right invalid and valid array, pls advise.
Your best bet is to use a promise:
api.post('/userlist', (req, res) => {
// Takes a username and returns a promise for information on that username.
function findByUsername(username) {
return new Promise((resolve, reject) =>
User.findOne({username}).exec((err, user) =>
err ? reject(err) : resolve(user)
)
);
}
// Iterate the array and transform each user to a promise for data on that user.
Promise.all(req.body.userlist.map(findByUsername))
// Then, when all of the promises in that new array resolve
.then(allUserDataInOrder => {
// Find all the valid ones (if (user))
let Valid = allUserDataInOrder.filter(Boolean); // Only those who are truthy
// And all the invalid ones (if (!user))
let Invalid = allUserDataInOrder.filter(userData => !userData); // Sadly, no convenient function here :(
// And send both away
res.send({Valid, Invalid}); // Short syntax FTW!
})
.catch(res.send); // Called with error object if any.
});
While these other solutions solve what you're trying to accomplish, they still incorporate bad design by iterating findOne(). Executing 1 query for every item in your list is incredibly inefficient. Using an $in query and a basic map, you can use a single query:
var User = require('../../db/models/user');
api.post('/userlist', function(req, res) {
User.find({username: {$in: req.body.userlist}}, function(err, users) {
if (err) {
return res.send(err);
}
// create a map of all the users in your list that exist in your database
var dbUserMap = {};
users.forEach(function(user) {
dbUserMap[user.username] = true;
});
var valid = [];
var invalid = [];
// check your POST list against the database map
req.body.userlist.forEach(function(username){
if (dbUserMap[username]) {
valid.push(username);
}
else {
invalid.push(username);
}
});
res.send({
valid: valid,
invalid: invalid
});
});
});
Try to use async module:
var invalid = [];
var valid = [];
async.each(req.body.userlist, function(name, next) {
User.findOne({username: name}, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
invalid.push(name);
} else {
valid.push(name);
}
next();
)};
}, function(err) {
if (err) {
return res.send(err);
}
res.send({
Invalid: invalid,
Valid: valid
});
});

Categories

Resources