只有当字段包含 ObjectId 时,是不是可以让猫鼬填充混合字段?

Posted

技术标签:

【中文标题】只有当字段包含 ObjectId 时,是不是可以让猫鼬填充混合字段?【英文标题】:Is it possible to have mongoose populate a Mixed field only if the field contains an ObjectId?只有当字段包含 ObjectId 时,是否可以让猫鼬填充混合字段? 【发布时间】:2018-03-04 13:55:52 【问题描述】:

设置

假设我们有FooBar 的模式。 Foo 有一个字段 bar。此字段可以包含引用文档 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);

问题

现在假设我们有一堆 Foo 文档。

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

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

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

但是,此方法会在遇到 bar 字段中不是 ObjectId 的对象时抛出异常,而不是让它们保持原样。

UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝 id:1):CastError:转换为 ObjectId 失败,因为模型“Bar”的路径“_id”处的值“一些任意对象”

尝试寻找解决方案

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

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

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

问题

那么我的问题是,如果字段包含 ObjectId,是否有任何方法可以让猫鼬只使用 populate 字段,否则不理会它?

【问题讨论】:

你可以在 find 上添加一个 post hook?,在那里你可以检查 prop 是 ObjectId 还是其他东西,如果它是 ObjectId,你搜索它并将其附加到对象,如果不是,您可以直接调用 next() 而不做任何更改。 @SebastiánEspinosa 这听起来可行。但是,不利的一面是,每次我调用Foo.find() 时,它都会自动填充,即使我不调用populate()。因此,在不需要时,我将无法“选择退出”填充。如果我理解正确? 你添加一个静态方法而不是一个钩子 【参考方案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);
);

优雅的做法是将其包装在模型上的 post hook 或静态方法中。

另一种选择是发送 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 个查询(以及所有人口查询),但也许这对您来说不是问题。可读性要好得多。当然,您随后可以更改查找查询以具体匹配您的情况。

【讨论】:

以上是关于只有当字段包含 ObjectId 时,是不是可以让猫鼬填充混合字段?的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB:如何找出数组字段是不是包含元素?

GraphQL 查询:如果不为空,则仅包含字段

GraphQL 查询:如果不为空,则仅包含字段

Mongoose 在结果的 _id 字段中返回“new ObjectId”

如何匹配MongoDB中的子文档数组?

在 Mongodb 中通过 ObjectId 查找有多快?