处理猫鼬人口例外情况

时间:2018-04-04 03:30:22

标签: node.js mongodb mongoose promise

我们有一些Mongoose(5.x)模型,并使用ref和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'
    }
});

postSchema模型的domain属性最初是String类型,最近已升级为ObjectID Ref。现有数据现在是混合的 - 大多数帖子都有一个字符串作为域名,而少数帖子有一个ObjectId。删除这些数据并重新开始会很简单,但我决定让代码优雅地处理这个并以正确的方式处理它。

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

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

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

  

获取帖子时出错CastError:Cast为ObjectId的值失败   " www.google.com"在路径" _id" for model" Domain" [2]   (节点:5740)

     

UnhandledPromiseRejectionWarning:未处理的承诺拒绝   (rejection id:1):CastError:对于值,转换为ObjectId失败   " www.google.com"在路径" _id" for model" Domain"

为什么我收到UnhandledPromseRejectionWarning,是不是处理拒绝的.catch()?

当遇到错误时,我想要两种可能的结果之一:

  • 将该文档的域设置为null
  • 如果无法做到这一点,请从结果集中排除该文档并继续

这些选项中的任何一个都可以吗?

2 个答案:

答案 0 :(得分:1)

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

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

通过这种方式,您可以使用'字符串'从结果中排除所有文档。域。

顺便说一句,最好的解决方案是使数据同质化,也许使用一个循环,为所有字符串域找到正确的域文档,并使用其_id作为参考。

答案 1 :(得分:1)

您可以尝试使用custom schema types

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