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