提问者:小点点

处理猫鼬种群异常


我们有一些Mongoose(5.x)模型,并且正在使用ref和populate来获取一些孩子。当populate失败时,我很难处理异常。

const postSchema = new mongoose.Schema({
    title: {
        type: String,
    },
    url : {
        type: String,
    },
    domain:{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Domain'
    },
    user:{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    }
});

后架构模型的domain属性最初是String类型,最近已升级为ObjectID引用。现有的数据现在是混合的--大多数帖子都有一个string作为域,而少数帖子有一个ObjectID。删除这些数据并重新开始是很简单的,但我决心让代码优雅地处理这些数据,并以适当的方式处理这些数据。

我们有一个(简化的)查询:

const posts = model.find().limit(20).populate('user').populate('domain');
posts.catch(err => console.log('Error getting posts ' + err);

运行此查询会引发一些预期错误和一些意外错误。这些错误会阻止endpoint返回任何数据。

获取posts casterror时出错:将模型“domain”[2]的路径“_id”处的值“www.google.com”转换为ObjectId失败(节点:5740)

UnhandledPromiseRejectionWarning:未处理的promise拒绝(拒绝ID:1):CastError:将模型“domain”的路径“_id”处的值“www.google.com”转换为ObjectId失败

为什么我会收到UnhandledPromseRejectionWarning,而不是。catch()处理拒绝?

当遇到错误时,我希望出现两种可能的结果之一:

  • 将该文档的域设置为null
  • 如果不可能,请从结果集中排除该文档,然后继续

这两种选择中的任何一种都可能吗?


共2个答案

匿名用户

您可以尝试使用$type运算符:

const posts = model.find({ domain: { $type: 'objectId' } }).limit(20).populate('user').populate('domain');

通过这种方式,您可以从结果中排除所有具有“字符串”域的文档。

顺便说一下,最好的解决方案是使数据具有同构性,可能使用一个循环,为所有字符串域查找正确的域文档,并使用itsid作为ref。

匿名用户

您可以尝试使用自定义模式类型

const mongoose = require('mongoose');
const {ObjectId} = mongoose.Schema.Types;
if (!('DomainId' in mongoose.Schema.Types)) {
  class DomainId extends mongoose.SchemaType {
    constructor (value, options) {
      value = (value instanceof ObjectId) ? value : new ObjectId(value);
      super(value, options, 'DomainId');

    }
    cast (val) {
      const _val = (value instanceof ObjectId) ? value : new ObjectId(value);
      return _val;
    }
  }
  mongoose.SchemaTypes.DomainId = DomainId;
}