如何在更新期间检查该数据是不是已存在于数据库中(Mongoose And Express)
Posted
技术标签:
【中文标题】如何在更新期间检查该数据是不是已存在于数据库中(Mongoose And Express)【英文标题】:How to check if that data already exist in the database during update (Mongoose And Express)如何在更新期间检查该数据是否已存在于数据库中(Mongoose And Express) 【发布时间】:2013-05-28 18:56:32 【问题描述】:如何在mongoose中保存编辑后的数据之前进行验证?
例如,如果sample.name
已经存在于数据库中,用户会收到某种错误,类似的,下面是我的代码
//Post: /sample/edit
app.post(uri + '/edit', function (req, res, next)
Sample.findById(req.param('sid'), function (err, sample)
if (err)
return next(new Error(err));
if (!sample)
return next(new Error('Invalid reference to sample information'));
// basic info
sample.name = req.body.supplier.name;
sample.tin = req.body.supplier.tin;
// contact info
sample.contact.email = req.body.supplier.contact.email;
sample.contact.mobile = req.body.supplier.contact.mobile;
sample.contact.landline = req.body.supplier.contact.landline;
sample.contact.fax = req.body.supplier.contact.fax;
// address info
sample.address.street = req.body.supplier.address.street;
sample.address.city = req.body.supplier.address.city;
sample.address.state = req.body.supplier.address.state;
sample.address.country = req.body.supplier.address.country;
sample.address.zip = req.body.supplier.address.zip;
sample.save(function (err)
if (err)
return next(new Error(err));
res.redirect(uri + '/view/' + sample._id);
);
);
);
【问题讨论】:
【参考方案1】:通常您可以使用mongoose validation,但由于您需要异步结果(数据库查询现有名称)并且验证器不支持承诺(据我所知),您需要创建自己的函数并传递打回来。这是一个例子:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
mongoose.connect('mongodb://localhost/testDB');
var UserSchema = new Schema(
name: type:String
);
var UserModel = mongoose.model('UserModel',UserSchema);
function updateUser(user,cb)
UserModel.find(name : user.name, function (err, docs)
if (docs.length)
cb('Name exists already',null);
else
user.save(function(err)
cb(err,user);
);
);
UserModel.findById(req.param('sid'),function(err,existingUser)
if (!err && existingUser)
existingUser.name = 'Kevin';
updateUser(existingUser,function(err2,user)
if (err2 || !user)
console.log('error updated user: ',err2);
else
console.log('user updated: ',user);
);
);
更新:更好的方法
pre 钩子似乎是一个更自然的停止保存的地方:
UserSchema.pre('save', function (next)
var self = this;
UserModel.find(name : self.name, function (err, docs)
if (!docs.length)
next();
else
console.log('user exists: ',self.name);
next(new Error("User exists!"));
);
) ;
更新 2:异步自定义验证器
看起来 mongoose 现在支持异步自定义验证器,所以这可能是自然的解决方案:
var userSchema = new Schema(
name:
type: String,
validate:
validator: function(v, cb)
User.find(name: v, function(err,docs)
cb(docs.length == 0);
);
,
message: 'User already exists!'
);
【讨论】:
如果用户存在,你没有调用“next()”,我认为你应该调用 next() 并出现错误 为什么不在名称字段中使用unique
参数?
用户将如何使用 save() 方法?
当我在pre
中间件中放入find
时出现此错误:Uncaught TypeError: Object #<Object> has no method 'find'
使用唯一索引是这里的最佳做法。否则,您必须在插入之前查询集合,而如果您使用唯一索引 mongodb 只会拒绝插入,从而节省往返时间和查询集合所花费的时间。唯一索引将是这里最好的解决方案。【参考方案2】:
继续使用@nfreeze 示例的另一种方法是这种验证方法:
UserModel.schema.path('name').validate(function (value, res)
UserModel.findOne(name: value, 'id', function(err, user)
if (err) return res(err);
if (user) return res(false);
res(true);
);
, 'already exists');
【讨论】:
什么是路径?你能详细说明一下吗 这对我有用,似乎是最优雅的方式,但它会引发弃用错误,即 DeprecationWarning: Implicit async custom validators (custom validators that take 2 arguments) is deprecated in mongoose >= 4.9 .0. mongoosejs.com/docs/validation.html#async-custom-validators 即使您不想使用异步验证器,也要小心,因为 mongoose 4 会假定所有接受 2 个参数的函数都是异步的,例如 validator.isEmail 函数。从 4.9.0 开始,此行为被视为已弃用,您可以通过在自定义验证器上指定 isAsync: false 来关闭它。【参考方案3】:除了已经发布的示例之外,这里还有另一种使用 express-async-wrap 和异步函数 (ES2017) 的方法。
路由器
router.put('/:id/settings/profile', wrap(async function (request, response, next)
const username = request.body.username
const email = request.body.email
const userWithEmail = await userService.findUserByEmail(email)
if (userWithEmail)
return response.status(409).send(message: 'Email is already taken.')
const userWithUsername = await userService.findUserByUsername(username)
if (userWithUsername)
return response.status(409).send(message: 'Username is already taken.')
const user = await userService.updateProfileSettings(userId, username, email)
return response.status(200).json(user: user)
))
用户服务
async function updateProfileSettings (userId, username, email)
try
return User.findOneAndUpdate('_id': userId,
$set:
'username': username,
'auth.email': email
, new: true)
catch (error)
throw new Error(`Unable to update user with id "$userId".`)
async function findUserByEmail (email)
try
return User.findOne('auth.email': email.toLowerCase())
catch (error)
throw new Error(`Unable to connect to the database.`)
async function findUserByUsername (username)
try
return User.findOne('username': username)
catch (error)
throw new Error(`Unable to connect to the database.`)
// other methods
export default
updateProfileSettings,
findUserByEmail,
findUserByUsername,
资源
async function
await
express-async-wrap
【讨论】:
【参考方案4】:对于任何陷入这种旧解决方案的人。有一个更好的方法 from the mongoose docs.
var s = new Schema( name: type: String, unique: true );
s.path('name').index( unique: true );
【讨论】:
(node:18024) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
哎呀。使用mongoose.connect(DATABASE_URL, useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true , err => ...
排除所有警告...【参考方案5】:
这是用更少的代码完成此任务的另一种方法。
更新 3:异步模型类静态
类似于选项 2,这允许您创建一个直接链接到架构的函数,但使用模型从同一个文件中调用。
model.js
userSchema.statics.updateUser = function(user, cb)
UserModel.find(name : user.name).exec(function(err, docs)
if (docs.length)
cb('Name exists already', null);
else
user.save(function(err)
cb(err,user);
);
从文件调用
var User = require('./path/to/model');
User.updateUser(user.name, function(err, user)
if(err)
var error = new Error('Already exists!');
error.status = 401;
return next(error);
);
【讨论】:
【参考方案6】:如果电子邮件或电话号码已存在于数据库中,请使用一个查询进行检查
let userDB = await UserS.findOne( $or: [
email: payload.email ,
phoneNumber: payload.phoneNumber
] )
if (userDB)
if (payload.email == userDB.email)
throw new BadRequest( message: 'E-mail already exists' )
else if (payload.phoneNumber == userDB.phoneNumber)
throw new BadRequest( message: 'phoneNumber already exists' )
【讨论】:
【参考方案7】:如果您通过唯一索引进行搜索,那么使用 UserModel.count 实际上可能比 UserModel.findOne 更适合您,因为它返回整个文档(即进行读取)而不是只返回一个 int。
【讨论】:
【参考方案8】:有一个更简单的方法使用the mongoose exists function
router.post("/groups/members", async (ctx) =>
const group_name = ctx.request.body.group_membership.group_name;
const member_name = ctx.request.body.group_membership.group_members;
const GroupMembership = GroupModels.GroupsMembers;
console.log("group_name : ", group_name, "member : ", member_name);
try
if (
(await GroupMembership.exists(
"group_membership.group_name": group_name,
)) === false
)
console.log("new function");
const newGroupMembership = await GroupMembership.insertMany(
group_membership: [
group_name: group_name, group_members: [member_name] ,
],
);
await newGroupMembership.save();
else
const UpdateGroupMembership = await GroupMembership.updateOne(
"group_membership.group_name": group_name ,
$push: "group_membership.$.group_members": member_name ,
);
console.log("update function");
await UpdateGroupMembership.save();
ctx.response.status = 201;
ctx.response.message = "A member added to group successfully";
catch (error)
ctx.body =
message: "Some validations failed for Group Member Creation",
error: error.message,
;
console.log(error);
ctx.throw(400, error);
);
【讨论】:
以上是关于如何在更新期间检查该数据是不是已存在于数据库中(Mongoose And Express)的主要内容,如果未能解决你的问题,请参考以下文章