修改 Mongoose 预保存挂钩中的对象
Modify object in Mongoose pre-save hook
在 GeoJSON 多边形(或更严格地说:LinearRing)中,最后一组坐标需要评估为与第一组坐标相同的值:
[[0,0], [0,1], [1,1], [1,0]] // bad
[[0,0], [0,1], [1,1], [1,0], [0,0]] // good
在使用 Mongoose 将 GeoJSON 多边形保存到我的 MongoDB 实例时,我想做一些宽松的验证(即修复对象,而不是拒绝它)。
我这样做:
export type Coordinates = number[]
// model object
export class Polygon {
type: string;
coordinates?: Coordinates[];
constructor(coordinates?: Coordinates[]) {
this.type = "Polygon";
this.coordinates = coordinates;
}
}
// schema object
export const PolygonSchema = {
type: String,
coordinates: [[Number]],
};
// model-schema binding
const polygonSchema = new mongoose.Schema(PolygonSchema, { typeKey: '$type' }).loadClass(Polygon);
// pre-save hook
polygonSchema.pre('save', async (next, opts) => {
// @ts-ignore
const pol: Polygon = this; // I find this assignment everywhere in documentation, but it seems to fail
if (pol?.coordinates?.length > 1 && pol.coordinates[0] !== pol.coordinates[pol.coordinates.length - 1]) {
pol.coordinates.push(pol.coordinates[0]);
}
next();
});
tsc
抱怨this
永远是undefined,调试的时候pol
对象确实是undefined。但是,根据 Visual Studio 调试器,this
不是。
是否可以在预保存挂钩期间修改对象,或者我需要事先这样做吗?
注意事项,以防万一:在我的 MongoDB 实例中,多边形将始终是 子文档:它被保存为另一个对象的形状。
如果您将箭头函数而不是传统函数传递给 pre('save', ...)
函数,则它不会为您提供访问文档的权限。箭头函数没有 this
绑定,而是使用父作用域。
Arrow functions don't have their own bindings to this, arguments or super, and should not be used as methods.
将箭头更改为传统函数定义
来自
polygonSchema.pre('save', {document: true, query: true}, async (next, opts) => {...}
至
polygonSchema.pre('save', {document: true, query: true}, async function (next, opts) {...}
这竟然是我没想到的问题。显然,您无权访问匿名(箭头)函数中的 this
对象(来源:https://youtu.be/DZBGEVgL2eE?t=1495)。我不知道这意味着在 JavaScript 一般情况下还是在 Mongoose 中,具体而言,但问题是通过这样做解决的:
const polygonSchema = new mongoose.Schema(PolygonSchema, { typeKey: '$type' }).loadClass(Polygon);
async function preSave() {
// @ts-ignore
const pol: Polygon = this;
if (pol?.coordinates?.length && pol.coordinates[0] !== pol.coordinates[pol.coordinates.length - 1]) {
pol.coordinates.push(pol.coordinates[0]);
}
}
polygonSchema.pre('save', preSave);
在 GeoJSON 多边形(或更严格地说:LinearRing)中,最后一组坐标需要评估为与第一组坐标相同的值:
[[0,0], [0,1], [1,1], [1,0]] // bad
[[0,0], [0,1], [1,1], [1,0], [0,0]] // good
在使用 Mongoose 将 GeoJSON 多边形保存到我的 MongoDB 实例时,我想做一些宽松的验证(即修复对象,而不是拒绝它)。
我这样做:
export type Coordinates = number[]
// model object
export class Polygon {
type: string;
coordinates?: Coordinates[];
constructor(coordinates?: Coordinates[]) {
this.type = "Polygon";
this.coordinates = coordinates;
}
}
// schema object
export const PolygonSchema = {
type: String,
coordinates: [[Number]],
};
// model-schema binding
const polygonSchema = new mongoose.Schema(PolygonSchema, { typeKey: '$type' }).loadClass(Polygon);
// pre-save hook
polygonSchema.pre('save', async (next, opts) => {
// @ts-ignore
const pol: Polygon = this; // I find this assignment everywhere in documentation, but it seems to fail
if (pol?.coordinates?.length > 1 && pol.coordinates[0] !== pol.coordinates[pol.coordinates.length - 1]) {
pol.coordinates.push(pol.coordinates[0]);
}
next();
});
tsc
抱怨this
永远是undefined,调试的时候pol
对象确实是undefined。但是,根据 Visual Studio 调试器,this
不是。
是否可以在预保存挂钩期间修改对象,或者我需要事先这样做吗?
注意事项,以防万一:在我的 MongoDB 实例中,多边形将始终是 子文档:它被保存为另一个对象的形状。
如果您将箭头函数而不是传统函数传递给 pre('save', ...)
函数,则它不会为您提供访问文档的权限。箭头函数没有 this
绑定,而是使用父作用域。
Arrow functions don't have their own bindings to this, arguments or super, and should not be used as methods.
将箭头更改为传统函数定义
来自
polygonSchema.pre('save', {document: true, query: true}, async (next, opts) => {...}
至
polygonSchema.pre('save', {document: true, query: true}, async function (next, opts) {...}
这竟然是我没想到的问题。显然,您无权访问匿名(箭头)函数中的 this
对象(来源:https://youtu.be/DZBGEVgL2eE?t=1495)。我不知道这意味着在 JavaScript 一般情况下还是在 Mongoose 中,具体而言,但问题是通过这样做解决的:
const polygonSchema = new mongoose.Schema(PolygonSchema, { typeKey: '$type' }).loadClass(Polygon);
async function preSave() {
// @ts-ignore
const pol: Polygon = this;
if (pol?.coordinates?.length && pol.coordinates[0] !== pol.coordinates[pol.coordinates.length - 1]) {
pol.coordinates.push(pol.coordinates[0]);
}
}
polygonSchema.pre('save', preSave);