繁体   English   中英

仅当字段包含ObjectId时,猫鼬才能填充“混合”字段吗?

[英]Is it possible to have mongoose populate a Mixed field only if the field contains an ObjectId?

设定

假设我们有FooBar架构。 Foo有一个bar 该字段可以包含引用文档Bar的ObjectId,也可以包含不是ObjectIds的其他任意对象。

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文档。

我希望能够在bar字段上使用猫鼬的populate来自动将Bar文档的引用替换为实际的Bar文档本身。 我还希望保留所有未引用Bar文档的其他对象。

通常,我会使用类似的方法来获取所有Foo文档,然后填充bar栏:

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

但是,此方法在bar字段中遇到非ObjectId的对象时会抛出异常,而不是使其保持不变。

UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:1):CastError:模型“ Bar”的路径“ _id”上的值“某些任意对象”的CastId失败

尝试寻找解决方案

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

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

不幸的是,错误是相同的。

所以我的问题是,有什么方法可以让猫鼬只populate一个字段包含ObjectId的情况下populate该字段,否则将其保留?

据我所知,您不能使用填充方式。 选择属性在尝试获取人口值之后才起作用,并且在此之前无法对其进行过滤。

您将必须手动执行。 您可以手动执行。

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个查询(以及所有人口查询),但这也许对您来说不是问题。 可读性好得多。 当然,您可以更改查找查询以专门匹配您的案例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM