Node.js Joi验证-如何根据数组中存在的另一个键来要求或选择字段?

Node.js Joi验证-如何根据数组中存在的另一个键来要求或选择字段?,node.js,validation,schema,joi,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, '

我有一个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\u name”和“contact.last\u name”以及“contact.phone”
存在时,每个元素才会有“address.place”字段(或者根据架构正确填充)

如何才能做到这一点?

您可以使用并创建如下模式:

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,所以很容易理解

基本上,我们在这里所说的是,如果联系人。名字联系人。姓氏联系人。电话存在,那么地址地址。地点是必需的,否则地址。地点是禁止的

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

{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    }
}
{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    },
    contact: {
    }
}
这将失败,因为地址.place不存在:

{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    }
}
{
    address: {
        first_name: 'a',
        last_name: 'b',
        phone: 'c'
    },
    contact: {
    }
}
最后,根据定义的模式,此对象将通过:

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

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

请注意,从我的答案到Soltex的答案的变化: 他将when“contact.first\u name”contact.last\u name“contact.phone”改为:Joi.exists()。这是不好的,因为在这种情况下,即使是空对象也“存在”,然后要求用户提供“address.place”。我们不想要这样的东西,我们需要在每个字段中至少有一个字符


另外,Soltex答案中的otherwise语句使用了Joi.forbidden(),虽然这不是这里想要的行为-我们仍然需要允许用户提供位置,即使没有联系人,但这不应该是强制性的-因此我使用了:Joi.optional()相反。

您的解决方案很好,但需要纠正。您必须调整您的模式-因为在这个模式中,当用户清除“address.place”属性时,它仍然是一个空对象,并且需要它。请看我的答案,更新你自己到它,然后我会删除我的,并标记为正确的答案你。