Joi验证-数组中如何存在基于另一个键的要求字段或可选字段?

时间:2019-06-03 08:21:57

标签: node.js validation schema joi

我有这个Joi模式:

  let schema = {};

  let stations = {
    contact: {
      first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
      last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
      phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
    },
    address: {
      place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').required().error(JoiCustomErrors),
      city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
      street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
      house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
    },
    passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
    notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
  };
  schema.stations = Joi.array().items(stations).min(1).max(5).required().error(JoiCustomErrors);

如您所见,schema.stations是最小1个元素和最大5个元素的数组。 我希望只有在"contact.first_name" AND "contact.last_name" AND "contact.phone"存在(或根据架构正确填充)的情况下,每个元素才具有“ address.place”字段。

我该怎么做?

2 个答案:

答案 0 :(得分:1)

您可以使用Joi.when()并创建如下所示的模式:

Joi.object().keys({
    contact: Joi.object().keys({
        first_name: Joi.string(),
        last_name: Joi.string(),
        phone: Joi.string(),
    }),
    address: Joi.object().keys({
        place: Joi.string(),
        city: Joi.string().min(2).max(30),
        street: Joi.string(),
        house_number: Joi.string()
    }).when('contact', {
        is: Joi.object().keys({
            first_name: Joi.exist(),
            last_name: Joi.exist(),
            phone: Joi.exist(),
        }),
        then: Joi.object({ place: Joi.required() }).required(),
        otherwise: Joi.object({ place: Joi.forbidden() })
    }),
    passengers_amount: Joi.number(),
    notes: Joi.string()
});

我只是简化了您的shema,所以很容易理解。

基本上,我们在这里所说的是,如果 concat.first_name concat.last_name concat.phone 存在 < / em>,则地址 address.place 是必需的,否则 address.place 禁止的

例如,此对象将失败,因为地址不存在:

{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    }
}

,这将失败,因为 address.place 不存在:

{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    },
    concact: {
    }
}

最后,根据定义的架构,该对象将通过:

{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    },
    concact: {
        place: 'd'
    }
};

答案 1 :(得分:0)

感谢Soltex,这就是应该使用的正确模式(但是请参考我所做的更改):

Joi.object().keys({
    contact: {
      first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
      last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
      phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
    },
    address: Joi.object().keys({
      place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').error(JoiCustomErrors),
      city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
      street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
      house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
    }).when('contact', {
      is: Joi.object().keys({
        first_name: Joi.string().min(1),
        last_name: Joi.string().min(1),
        phone: Joi.string().min(1),
      }),
      then: Joi.object({ place: Joi.required() }).required(),
      otherwise: Joi.object({
        place: Joi.optional().allow("")
      })
    }),
    passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
    notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
  })

请注意,从我的答案更改为Soltex的答案: 他将“ contact.first_name”“ contact.last_name”“ contact.phone” 设置为: Joi.exists() 。这不好,因为以这种方式甚至“存在”一个空对象,然后要求用户提供“ address.place”。我们不需要这样的东西,我们需要在每个字段中至少保留一个字符。

此外,Soltex答案中的else语句使用的是 Joi.forbidden(),尽管这不是此处的预期行为-我们仍然需要允许用户提供位置,即使没有联系人,但这不是必须的-因此,我改用了: Joi.optional()