问题
当使用 mongoose 按特定字段查找文档时,如果字段的类型与查询值的类型不同,则 mongoose 将尝试将查询值转换为与字段相同的类型。
但是,如果无法转换该值,则 mongoose 将抛出一个 CastError
。
此行为可以在以下示例中看到,其中 mongoose 在尝试查询 时将尝试将字符串
文档的 'invalid object id'
转换为 ObjectId
>Foobar
字段:
const fooSchema = new mongoose.Schema({
bar: {
type: mongoose.Schema.Types.ObjectId,
}
});
const Foo = <any>mongoose.model<any>('Foo', fooSchema);
await Foo.findOne({ bar: 'invalid object id' });
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): CastError: Cast to ObjectId failed for value "invalid object id" at path "bar" for model "Foo"
(如果 bar
是一些其他类型,例如 Number
或 Boolean
也会出现类似的错误。)
但是,我不喜欢这种行为。我非常希望返回的文档简单地变为 null
,而不会引发错误。毕竟,如果无法转换查询中的值,那么文档在逻辑上也不可能存在于给定查询下。
现在,我知道我可以在构造查询之前简单地进行检查以确保我不会传入无法转换的类型。但是,我不喜欢这种方法,因为它导致不得不重复代码。通常,处理类型无效时发生的事情的代码与处理文档不存在时发生的事情的代码完全相同。
此外,我也不想完全禁用类型检查。因此,将字段类型更改为 Mixed
不是解决方案,因为我希望在创建新文档时类型检查仍然存在。
尝试的解决方案
所以我试图通过创建自定义 query helpers 来解决这个问题检查类型,无效则返回null,有效则执行查询。
fooSchema.query.byBar = function(id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return null;
}
return this.where('bar').equals(id);
};
然后我可以将其与 Foo.findOne().byBar('invalid object id')
一起使用。
然而,这个解决方案的问题在于它不再是可链接的。这意味着如果我要尝试诸如 Foo.findOne().byBar('invalid object id').lean()
之类的操作,如果类型检查失败(但会通过类型检查时工作正常):
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'lean' of null
尝试改用静态方法会遇到同样的问题。
fooSchema.statics.findOneByBar = function(id: any) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return null;
}
return this.findOne({ bar: id });
};
问题
所以本质上,如果类型检查失败,我希望能够让查询返回 null
,但仍然可以链接。我希望查询是可链接的,因为我仍然希望能够在类型有效的情况下指定其他查询条件。
现在,如果我尝试的解决方案是在正确的轨道上,那么我需要做的不是在类型检查失败时直接返回 null
,而是从可链接的查询构建器 api 返回一些东西将导致查询的最终结果为 null
。我基本上需要某种 1=0
query condition (但是,链接的问题没有为 1=0
条件提出有保证的答案)。所以我的问题是,如果我尝试的解决方案是在正确的轨道上,那么我返回什么是一个可链接的 Mongoose 查询,但会导致查询在查询时始终导致 null
执行了吗?
或者,如果我尝试的解决方案走错了路,是否有另一种方法可以使 mongoose 查找查询结果为 null
而不是抛出 CastError
当类型不兼容时?
最佳答案
可能是我的回答有点愚蠢和直截了当。但我想这样做。
fooSchema.statics.findOneByBar = function(id: any) {
if (!mongoose.Types.ObjectId.isValid(id)) {
id = "111111111111111111111111"; // other values are also possible
}
return this.findOne({ bar: id });
};
这是一个有效的 objectId
,它可能永远不会被 Mongodb 生成。因此,这样查询将是有效的,并且所有可链接的功能都将完好无损。让我知道它是否对您有帮助。
关于javascript - 当类型不兼容时,如何使 Mongoose 查找查询返回 null 而不是抛出 CastError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49204683/