我试图创建一个" findOneAndUpdate"查询将触发预验证中间件。
需要这些中间件来验证给定的坐标并创建一个“id”。字段(是的,不' _id' one)在请求的正文中没有提供。
正如您在下面看到的那样(查看代码中的注释),我已经关闭了,但不明白为什么mongo
引发的错误是重复的关键品种。
也许承诺不是去往这里的方式,尽管它们让我的成就不仅仅是链式pre
中间件。
以下是我的快递路线:
/* POST /geolocs */
router.post('/', function(req, res, next) {
Geoloc.create(req.body, function(err, post) {
if (err) return next(err);
res.status(201).json(post);
});
});
这是我的架构:
var GeolocSchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true
},
location: {
type: {
type: String,
default: 'Point',
required: true
},
coordinates: {
type: [Number],
required: true
}
},
count: Number
});
GeolocSchema.index({
location: '2dsphere'
});
预验证中间件:
// Before validation, check given coordinates for errors.
GeolocSchema.pre('validate', function(next) {
coord = this.location.coordinates
if (this.location.type && coord) {
if (Array.isArray(coord) && coord.length === 2) {
lat = coord[1];
lon = coord[0];
if ((-90 <= lat && lat <= 90) && (-180 <= lat && lat <= 180)) next();
}
}
var err = new Error('...'); // Long error text, irrelevant here
err.status = 400;
next(err);
});
// Then, if no 'id' is given, create it.
GeolocSchema.pre('validate', function(next) {
if (!this.id) {
strLat = this.location.coordinates[1].toFixed(3).replace('.', '_');
strLon = this.location.coordinates[0].toFixed(3).replace('.', '_');
this.id = strLat + '-' + strLon;
}
next();
});
我希望能够做的是在上面添加以下内容:
// Here, using the validate or save hook doesn't change anything.
GeolocSchema.pre('validate', function(next) {
var prom = Geoloc.findOne({
'id': {
$eq: this.id
}
}).exec();
prom.then((err, geoloc) => { // Arrow function here to access 'this'
if (err) next(err);
// If no geoloc was found, go ahead and save.
if (!geoloc) next();
// Else, update to increment the count (THIS WORKS).
return Geoloc.update({'id': this.id}, {$inc: {count: 1}}).exec();
}).then((toto) => {
// This doesn't work, the error thrown by mongo is a duplicate key error (E11000).
if (toto) next(new Error('204'));
else next(new Error("Something that shouldn't happen, happened..."));
});
});
答案 0 :(得分:1)
问题在于pre()
&amp; post()
的{{1}}中间件&amp; save
,validate
等未执行update()
。docs中提到了findOneAnUpdate()
以及GitHub issue
但是,有pre('findOneAndUpdate')
和post('findOneAndUpdate')
个钩子可用(不确定update
的挂钩是否有效)。
希望这会对你有所帮助。
答案 1 :(得分:1)
详细说明Santanu Biswas接受的答案,以下是基于它的工作代码:
请注意,它仍有一些怪癖,特别是关于响应中发送回客户端的内容,但MongoDB操作按预期发生。
快速路线:
router.post('/', function(req, res, next) {
Geoloc.findOneAndUpdate({
id: req.body.id
}, req.body, {
runValidators: true, // MANDATORY OPTION
upsert: true,
context: 'query' // MANDATORY OPTION
}, function(err, post) {
if (err) return next(err);
res.status(201).json(post);
});
});
预 findOneAndUpdate
中间件:
GeolocSchema.pre('findOneAndUpdate', function(next) {
doc = this.getUpdate();
coord = doc.location.coordinates;
if (doc.location.type && coord) {
if (Array.isArray(coord) && coord.length === 2) {
lat = coord[1];
lon = coord[0];
if ((-90 <= lat && lat <= 90) && (-180 <= lat && lat <= 180)) {
return next();
}
}
}
var err = new Error('...'); // Long error text, irrelevant here
err.status = 400;
next(err);
});
和
GeolocSchema.pre('findOneAndUpdate', function(next) {
doc = this.getUpdate();
query = this.getQuery();
if (!query.id) {
strLat = doc.location.coordinates[1].toFixed(3).replace('.', '_');
strLon = doc.location.coordinates[0].toFixed(3).replace('.', '_');
query.id = strLat + '-' + strLon;
doc.id = query.id;
}
var prom = Geoloc.findOne({
'id':query.id
}).exec();
prom.then((geoloc, err) => {
if (err) return next(err);
if (!geoloc) return next();
doc.count += geoloc.count;
next();
});
});