Javascript 只有当字段包含ObjectId时,mongoose才能填充混合字段吗? 安装程序
假设我们有Javascript 只有当字段包含ObjectId时,mongoose才能填充混合字段吗? 安装程序,javascript,node.js,typescript,mongoose,mongoose-populate,Javascript,Node.js,Typescript,Mongoose,Mongoose Populate,假设我们有Foo和Bar的模式Foo有一个字段bar。此字段可以包含引用文档栏的ObjectId,也可以包含其他非ObjectId的任意对象 const fooSchema = new mongoose.Schema({ bar: { type: mongoose.Schema.Types.Mixed, ref: 'Bar' } }); const Foo = <any>mongoose.model<any>('Foo', fooSchema);
Foo
和Bar
的模式Foo
有一个字段bar
。此字段可以包含引用文档栏的ObjectId,也可以包含其他非ObjectId的任意对象
const fooSchema = new mongoose.Schema({
bar: {
type: mongoose.Schema.Types.Mixed,
ref: 'Bar'
}
});
const Foo = <any>mongoose.model<any>('Foo', fooSchema);
const barSchema = new mongoose.Schema({
name: String
});
const Bar = <any>mongoose.model<any>('Bar', barSchema);
但是,当此方法在栏中遇到非objectid的对象时,将引发异常,而不是将其保持不变
未经处理的PromisejectionWarning:未经处理的承诺拒绝(拒绝id:1):CastError:在模型“Bar”的路径“\u id”处对值“某个任意对象”的转换失败
试图找到解决办法
我已使用填充
上的匹配
选项进行了检查,要求栏上存在一个字段
:
Foo.find().populate({
path: 'bar',
match: {
name: {
$exists: true
}
}
}
不幸的是,错误是相同的
问题:
所以我的问题是,如果字段包含ObjectId,有没有办法让mongoose只填充一个字段,而不填充它?据我所知,你不能用这种方式填充。“选择属性”在尝试获取填充值后工作,在此之前无法对其进行筛选
您必须手动执行此操作。你可以手工做
let foos = await Foo.find({});
foos = foos.map(function (f) {
return new Promise(function (resolve) {
if (condition()) {
Foo.populate(f, {path: 'bar'}).then(function(populatedF){
resolve(f);
});
} else {
resolve(f);
}
});
});
await Promise.all(foos).then(function (fs) {
res.status(200).json(fs);
});
优雅的做法是在模型上用post-hook或static方法包装它
另一个选项是发送2个查询:
const foosPopulated = Foo.find({ alma: { $type: 2 } }).populate('bar'); // type of string
const foosNotPopulated = Foo.find({ alma: { $type: 3 } }); // type of object
const foos = foosPopulated.concat(foosNotPopulated);
这当然是次优的,因为有2个查询(以及所有填充查询),但这对您来说可能不是问题。可读性更好。当然,您可以更改find查询以匹配您的具体情况。您可以在find maybe?上添加一个post钩子,在那里您可以检查道具是否是ObjectId或其他内容,如果是ObjectId,您可以搜索它并将其附加到对象,如果不是,您可以调用next(),而不做任何更改。@SebastiánEspinosa这听起来似乎可以工作。但是,缺点是每次我执行Foo.find()
,即使我没有调用populate()
,它都会自动填充。因此,在没有必要的情况下,我无法“选择退出”人口。如果我理解正确的话?你添加了一个静态方法而不是钩子
const foosPopulated = Foo.find({ alma: { $type: 2 } }).populate('bar'); // type of string
const foosNotPopulated = Foo.find({ alma: { $type: 3 } }); // type of object
const foos = foosPopulated.concat(foosNotPopulated);