我们有一些Mongoose(5.x)模型,并且正在使用ref和populate来获取一些孩子。当populate失败时,我很难处理异常。
const postSchema = new mongoose.Schema({
title: {
type: String,
},
url : {
type: String,
},
domain:{
type: mongoose.Schema.Types.ObjectId,
ref: 'Domain'
},
user:{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
后架构模型的domain属性最初是String类型,最近已升级为ObjectID引用。现有的数据现在是混合的--大多数帖子都有一个string作为域,而少数帖子有一个ObjectID。删除这些数据并重新开始是很简单的,但我决心让代码优雅地处理这些数据,并以适当的方式处理这些数据。
我们有一个(简化的)查询:
const posts = model.find().limit(20).populate('user').populate('domain');
posts.catch(err => console.log('Error getting posts ' + err);
运行此查询会引发一些预期错误和一些意外错误。这些错误会阻止endpoint返回任何数据。
获取posts casterror时出错:将模型“domain”[2]的路径“_id”处的值“www.google.com”转换为ObjectId失败(节点:5740)
UnhandledPromiseRejectionWarning:未处理的promise拒绝(拒绝ID:1):CastError:将模型“domain”的路径“_id”处的值“www.google.com”转换为ObjectId失败
为什么我会收到UnhandledPromseRejectionWarning,而不是。catch()处理拒绝?
当遇到错误时,我希望出现两种可能的结果之一:
这两种选择中的任何一种都可能吗?
您可以尝试使用$type运算符:
const posts = model.find({ domain: { $type: 'objectId' } }).limit(20).populate('user').populate('domain');
通过这种方式,您可以从结果中排除所有具有“字符串”域的文档。
顺便说一下,最好的解决方案是使数据具有同构性,可能使用一个循环,为所有字符串域查找正确的域文档,并使用itsid作为ref。
您可以尝试使用自定义模式类型
const mongoose = require('mongoose');
const {ObjectId} = mongoose.Schema.Types;
if (!('DomainId' in mongoose.Schema.Types)) {
class DomainId extends mongoose.SchemaType {
constructor (value, options) {
value = (value instanceof ObjectId) ? value : new ObjectId(value);
super(value, options, 'DomainId');
}
cast (val) {
const _val = (value instanceof ObjectId) ? value : new ObjectId(value);
return _val;
}
}
mongoose.SchemaTypes.DomainId = DomainId;
}