2017-09-22 73 views
0

设置

比方说,我们有模式FooBarFoo有一个字段bar。该字段可以包含引用文档Bar的ObjectId,也可以包含其他非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); 

问题

现在假设我们有一大堆的Foo文件。

我想能够使用猫鼬的populatebar场与实际Bar文档本身自动替换为Bar文件引用。我还想保留所有其他未引用Bar文档的对象。

通常情况下,我会用这样的事情让所有的Foo文档,然后填充bar领域:

Foo.find().populate('bar') 

然而,这种方法当它遇到的bar字段是对象将抛出一个异常而不是ObjectIds,而不是让它们保持原样。

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): CastError: Cast to ObjectId failed for value "Some arbitrary object" at path "_id" for model "Bar"

尝试寻求解决

我已经使用上populatematch选项检查,通过要求在Bar一个字段存在:

Foo.find().populate({ 
    path: 'bar', 
    match: { 
    name: { 
     $exists: true 
    } 
    } 
} 

不幸的是,该错误是一样的。

问题

所以我的问题是那么,有没有什么办法让猫鼬只有populate一个字段如果该字段包含的ObjectId和息事宁人,否则?

+0

你可以在find上添加一个post hook吗?,那么你可以检查prop是否是一个ObjectId或其他东西,如果它的ObjectId,你搜索并追加到对象,如果没有,你可以调用next()而不做任何改变。 –

+0

@SebastiánEspinosa听起来好像可以工作。然而,不利的一面是,即使我没有调用'populate()',每次我执行'Foo.find()'时,它都会自动填充。所以我不能在不需要的时候“退出”填充。如果我理解正确? – Zsw

+0

您添加一个静态方法而不是挂钩 –

回答

1

据我所知,你不能使用这种方式填充。尝试获取人口的值后选择属性工作,并且在此之前无法过滤它。

你必须手动完成。你可以手动完成。

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); 
}); 

优雅地将它包装在您的模型的后钩或静态方法。

另一种选择是派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个查询(和所有人口查询),但也许你这不会是一个问题。可读性要好得多。当然,你可以改变查询查询来特别匹配你的案例。