验证joi-所有数组元素都具有相同的嵌套值

2nc8po8w  于 2021-10-10  发布在  Java
关注(0)|答案(2)|浏览(316)

我想使用joi来验证传入的json请求对象,以便每个数组元素在路径上具有相同的值 .runs[].results.type . 如果有一个元素突出,验证就会失败。有点像 array.unique 结束 .results.type 在…内 .runs[] .
假设以下JSON是有效的输入:

{
  runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'A', side: 'right' }, meta: { createdBy: 1 } }
  ]
}

这将抛出一个验证错误:

{
  runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'B', side: 'right' }, meta: { createdBy: 1 } }
  ]
}

我尝试编写一个joi模式,如:

...
  runs: Joi.array()
    .min(1)
    .items(
      Joi.object()
        .unknown()
        .keys({
          results: Joi.object()
            .keys({
              type: Joi.string()
                .allow('A', 'B', 'C', 'D')
                .valid(Joi.ref('....', { in: true, adjust: runs => runs.map(run => run.results.type) }))
                .required(),
              side: Joi.string().allow('left', 'right')
            })
        })
    )
...

但这不起作用(我认为它最终会循环引用)。此外,即使它成功运行,我也不确定它是否会在两种不同类型的情况下破坏验证 AB 提供。

fslejnso

fslejnso1#

你需要使用 .some() o .every() 函数,该函数在至少有某个元素完成某个条件或每个元素完成某个条件时返回:
1) 使用 .some() :

const object1 = {
  runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'A', side: 'right' }, meta: { createdBy: 1 } }
  ]};

const object2 = {
runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'B', side: 'right' }, meta: { createdBy: 1 } }
  ]};

let result1 = object1.runs.some(e => e.results.type !== 'A');

console.log(result1);   // false

let result2 = object2.runs.some(e => e.results.type !== 'A');

console.log(result2);   // true

2) 使用 .every() :

const object1 = {
  runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'A', side: 'right' }, meta: { createdBy: 1 } }
  ]};

const object2 = {
runs: [
    { results: { type: 'A', side: 'left' }, meta: { createdBy: 3 } },
    { results: { type: 'B', side: 'right' }, meta: { createdBy: 1 } }
  ]};

let result1 = object1.runs.every(e => e.results.type === 'A');

console.log(result1);   // true

let result2 = object2.runs.every(e => e.results.type === 'A');

console.log(result2);   // false

如果您不知道目标值(在本例中为“a”),只需获取第一个类型值-> runs[0].results.type 并用它替换“a”。

6fe3ivhb

6fe3ivhb2#

我想我找到了一种不使用自定义函数的优雅解决方案,尽管这将是一个很好的解决方法!

Joi.object().keys({
  runs: Joi.array().items(
    Joi.object().keys({
      results: Joi.object().keys({
        type: Joi.string().valid(
          Joi.ref('....0.results.type')
        ).required() 
      })
    })
  ).has(
    Joi.object().keys({ 
      results: Joi.object().keys({
        type: Joi.valid('A', 'B', 'C', 'D').required()
      })
    }))
  })

这是基于首先确定所有 runs[] 元素的值相同 .results.type ,然后Assert runs 排列 .has() 至少有一个元素具有 .results.type 从…起 {'A', 'B', 'C', 'D'} .
有趣的是,在joi中,数组元素在 .ref() 喜欢 $runs.0.results .

相关问题