【问题标题】:The right way to connect to query database mongodb multiples times多次连接查询数据库mongodb的正确方法
【发布时间】:2018-07-17 01:15:13
【问题描述】:

我在空闲时间使用 nodejs/Handlebars.js/mongodb(mongoose) 建立一个网站, 我没有学习任何 Web 开发课程,我不知道有效和安全地做事的正确方法。 所以在这个项目中,我偶然发现了一个问题,我必须在数据库中查询电子邮件是否已经存在或不存在,它再次查询用户名是否已经存在,如果存在,用户可以注册到数据库。是的,它完成了工作,但我对这种方法不满意,它似乎不专业且不安全。 那你能告诉我正确的方法吗?

这是我认为我做错了的部分

	//check for errors in Req.validation and push them to errors Array
if(valErrors){
	for (var i = 0; i < valErrors.length; i++) {
	 	errors.push(valErrors[i])
	}
}
//check if the username submitted exists in the database 
User.findOne({'username':username}, function (err, user) {		
	if(user)
		{
			errors.push({msg:"username is already in use!"})				
			res.render('user/register',{
				errors:errors
			});
		}
        //if the username is not in use already check if the email is in 
        //use 
		else {
			User.findOne({'email':email}, function (err, user) {
				if(user){
					errors.push({msg:'email is already in use !'})		
					res.render('user/register',{
						errors:errors
					});			
				}	//if the email doesnt exists too then register this //user
				else{
					var coins = new Coins()
					var newUser = new User({
					name: name,
					email:email,
					username: username,
					password: password,
					coins:coins.encryptcoins('0'),
					joindate:getDate()
					});

					User.createUser(newUser, function(err, user){
						if(err) throw err;		
					});
					req.flash('success_msg', 'You are registered and can now login');
					res.redirect('/user/login');
					}	
				

			});
		}
});
		
})
编辑: 用户架构

var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');

// User Schema
var UserSchema = mongoose.Schema({
	username: {
		type: String,
		index:true,
		required:true
	},
	password: {
		type: String,
		required:true
	},
	email: {
		type: String,
		required:true
	},
	name: {
		type: String,
		required:true
	},
	coins: {
		type:String,
		required:true
	},
	joindate: {
		type:String,
		required:true
	},
	orders: {
		type:Array,
		required:false
	}
},{collection:'Users'});

var User = module.exports = mongoose.model('User', UserSchema);

module.exports.createUser = function(newUser, callback){
	bcrypt.genSalt(10, function(err, salt) {
	    bcrypt.hash(newUser.password, salt, function(err, hash) {
	        newUser.password = hash;
	        newUser.save(callback);
	    });
	});

}

module.exports.getUserByUsername = function(username, callback){
	var query = {username: username};
	User.findOne(query, callback);
}

module.exports.getUserById = function(id, callback){
	User.findById(id, callback);
}

module.exports.comparePassword = function(candidatePassword, hash, callback){
	bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
    	if(err) throw err;
    	callback(null, isMatch);
	});
}

这是整个代码

var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/users');
const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn();
const ensureLoggedOut = require('connect-ensure-login').ensureLoggedOut();
var Coins = require('../models/coins');
// Register
router.get('/register',ensureLoggedOut, function(req, res){
	res.render('user/register');
});

// Login
router.get('/login',ensureLoggedOut, function(req, res){
	res.render('user/login');
});

// Register User
router.post('/register', function(req, res){
	var name = req.body.name;
	var email = req.body.email;
	var username = req.body.username;
	var password = req.body.password;
	var password2 = req.body.password2;

	console.log(email)
	console.log(username)
	// Validation
	req.checkBody('name', 'Name is required').notEmpty();
	req.checkBody('email', 'Email is required').notEmpty();
	req.checkBody('email', 'Email is not valid').isEmail();
	req.checkBody('username', 'Username is required').notEmpty();
	req.checkBody('password', 'Password is required').notEmpty();
	req.checkBody('password2', 'Passwords do not match').equals(req.body.password);

	//Error handling
	var errors = [];
	var valErrors = req.validationErrors()
	//check for errors in Req.validation and push them to errors Array
	if(valErrors){
		for (var i = 0; i < valErrors.length; i++) {
		 	errors.push(valErrors[i])
		}
	}
    //check if the username submitted exists in the database 
	User.findOne({'username':username}, function (err, user) {		
		if(user)
			{
				errors.push({msg:"username is already in use!"})				
				res.render('user/register',{
					errors:errors
				});
			}
            //if the username is not in use already check if the email is in 
            //use 
			else {
				User.findOne({'email':email}, function (err, user) {
					if(user){
						errors.push({msg:'email is already in use !'})		
						res.render('user/register',{
							errors:errors
						});			
					}	//if the email doesnt exists too then register this //user
					else{
						var coins = new Coins()
						var newUser = new User({
						name: name,
						email:email,
						username: username,
						password: password,
						coins:coins.encryptcoins('0'),
						joindate:getDate()
						});

						User.createUser(newUser, function(err, user){
							if(err) throw err;		
						});
						req.flash('success_msg', 'You are registered and can now login');
						res.redirect('/user/login');
						}	
					

				});
			}
	});
			
})


passport.use(new LocalStrategy(
	function(username, password, done) {
		User.getUserByUsername(username, function(err, user){
			if(err) throw err;
			if(!user){
				return done(null, false, {message: 'Unknown User'});
			}

			User.comparePassword(password, user.password, function(err, isMatch){
				if(err) throw err;
				if(isMatch){
					return done(null, user);

				} else {
					return done(null, false, {message: 'Invalid password'});
				}
			});
		});
	}));

passport.serializeUser(function(user, done) {
	done(null, user.id);
});

passport.deserializeUser(function(id, done) {
	User.getUserById(id, function(err, user) {
		done(err, user);
	});
});

router.post('/login',
	passport.authenticate('local', {successReturnToOrRedirect: '/', failureRedirect:'/user/login',failureFlash: true}),
	function(req, res) {
		res.redirect('/');
	});

router.get('/logout',ensureLoggedIn, function(req, res){
	req.logout();
	req.session.destroy();
	res.redirect('/');

});

module.exports = router;








function getDate(){
	var d = new Date()
	return ("date: "+d.getDate()+"/"+(d.getMonth()+1)+"/" +d.getFullYear() + " time GMT+1: "+(d.getHours()+1)+":"+(d.getMinutes())).toString()
}









// replaced with Ensure loging in library !
// function ensureLoggedIn(req, res, next) {	
//   if(req.user){
//     return next()
//   }else{
//     res.redirect('/user/login');
//   }
// }
// function ensureLoggedOut(req, res, next) {	
//   if(!req.user){
//     return next()
//   }else{
//     res.redirect('/');
//   }
// }

【问题讨论】:

  • 能否请您发布您的数据库架构?您的数据看起来是相关的,因此,我看不出在 RDBMS 上使用 MongoDB 的原因。
  • 当然,我发布了用户模式,RDBMS 和 mongoDB 之间有什么区别?
  • 好吧,由于您的模式是规范化的形式(即没有嵌套字段),RDBMS 可能会在您的规模上产生更好的性能(我假设您希望每秒处理多达 1000 个事务并且没有额外的表格)。如果您想在多个节点中横向扩展并使用嵌套类型(如 JSON),MongoDB 将提供额外的功能和性能。
  • 好的,谢谢,但我想我会选择 mongodb(mongoose)。所以我用的方法没有问题?
  • 听起来不错。我会根据“合理”的数据库使用原则提出一些建议,相信你能弄清楚语法。我希望这会有所帮助。

标签: javascript node.js database mongodb mongoose


【解决方案1】:

一般来说,对于发送到数据库管理系统 (DBMS)(即 MongoDB 服务器)的逻辑工作单元,必须将各个操作分组到单个事务中。这样,您可以避免在数据库中同时创建用户可能导致的不一致。

更准确地说,在您的项目中,注册过程会检查以下内容:

  1. 检查电子邮件是否存在
  2. 检查用户名是否存在
  3. 如果查询 1 和 2 返回一个空结果集,请注册一个新用户

本质上,这 3 个步骤需要以原子方式发生,这意味着它们作为单个逻辑单元(事务)发生。如果不是,在极端情况下 2 个并发客户端尝试使用相同的用户名注册用户,那么您的数据库将导致两个用户具有相同的用户名。

因此,您应该更新您的代码以执行以下操作:

  1. 发起交易
  2. 检查具有给定电子邮件 (user_email) 和/或用户名 (user_name) 的用户
  3. 如果步骤2的查询返回了用户,则回滚事务;否则,使用user_emailuser_name 插入一个新用户。
  4. 提交事务

我不确定 MongoDB 是否支持事务一致性,这也是我建议使用 RDBMS 的原因之一。另外,如果没有,我相信您可以找出一个基于电子邮件/用户名识别单个用户的模式,并尝试将注册作为事务执行。

最后,使用存储过程在 DBMS 端进行大部分处理被认为是一种很好的做法。

我希望这会有所帮助。

【讨论】:

  • 谢谢你的帮助,是的,这就是我真正想做的。我尝试创建两个函数,一个用于检查电子邮件,如果存在则返回 true,如果不存在则返回 false,另一个函数对用户名执行相同操作,然后继续注册。然而,结果有点奇怪。由于nodejs是异步的,同时查询用户名和邮箱都需要时间,所以这两个函数在if语句中返回null,因为它们没有完成查询。
  • 我很高兴能帮上忙。请将我的帖子标记为答案,以便将问题标记为已关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多