我有这个功能。仅允许服务: 仅在可用参数为真时才采用。
function takeService(req, res) {
var serviceId = req.params.id;
var driverId = req.body.driverId;
Service.findById(serviceId, (err, service) =>{
if (!err) {
if (!service) {
res.status(404).send({message: 'Not found'});
} else {
if (service.available === false ) {
res.status(409).send({message: 'The service is taken'});
} else {
Service.findByIdAndUpdate(serviceId, {
driverId,
status: 1,
available: false
}, (err, serviceUpdated) =>{
if (!err && serviceUpdated) {
res.status(200).send({message: "tomado"});
}
});
}
}
}
});
}
架构:
var ServiceSchema = Schema({
clientId: {
type: String,
ref: 'Client'
},
available: Boolean,
routeId: {
type: String,
ref: 'Route'
},
date: Date,
radius: Number,
driverId: {
type: String,
ref: 'Driver'
},
status: Number,
time: String,
createdTime: Number,
rateId: {
type: String,
ref: 'Rate'
}
});
var DriverSchema = Schema({
name: String,
surname: String,
username: String,
password: String,
status: { type: Number, default: 0 },
oneSignalId: String,
plate: String,
make: String,
year: String,
model: String,
groupId: [{
type: String,
ref: 'DriverGroup'
}],
unit: String,
telephone: String
});
问题是当两个设备调用此函数时,在某些情况下,它们都找到文档并检查是否可用,然后两者都更新同一文档。我正在寻找模式中的一些验证来自动检查这个属性。
答案 0 :(得分:0)
如果我正确理解问题,主要问题是两台设备可能认为服务仍然可用。
这样做的最终原因是findById
和findByIdAndUpdate
之间存在竞争条件:在这两个电话之间,有一个时间窗口,其中另一个请求可以改变数据库中的文档。
要解决此问题,您可以使用原子findAndModify
命令,Mongoose将此命令公开为Model#findOneAndUpdate
。
您的代码会变成这样:
function takeService(req, res) {
var serviceId = req.params.id;
var driverId = req.body.driverId;
Service.findOneAndUpdate({
_id : serviceId,
available : true
}, {
driverId : driverId,
status : 1,
available : false,
}, (err, service) => {
if (err) {
return res.status(500);
} else if (! service) {
return res.status(409).send({message: 'The service is taken'});
} else {
return res.status(200).send({message: "tomado"});
}
});
}
您应该注意与原始代码存在一些差异:
serviceId
)和不再可用的服务;在这两种情况下,更新都不会产生任何结果,并且会发回409响应; findOneAndUpdate
将在更新之前返回旧文档。如果要接收更新的文档,请在查询中传递new
选项:
Service.findOneAndUpdate({ ... }, { ... }, { new : true }, (err, service) => { ... })
我在那里添加了一个错误处理程序,它会发回500("内部服务器错误" )响应。