我想使用 Joi 来验证传入的 JSON 请求对象,以便每个数组元素在路径.runs[].results.type
具有相同的值。如果有一个元素突出,则验证应该会失败。类似于array.unique
在.runs[]
内部.results.type
的反面.
将以下 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')
})
})
)
...
但这不起作用(我认为它最终以循环引用结束)。此外,即使它成功运行,我也不确定如果提供了两种差异类型A
和B
,它是否真的会破坏验证。
我想我在不使用自定义函数的情况下找到了一种优雅的解决方案,尽管这将是解决此问题的好方法!
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
值,然后断言runs
数组.has()
至少一个具有.results.type
来自{'A', 'B', 'C', 'D'}
的元素。
我学到的有趣的事情是,在Joi中,数组元素在.ref()
中用点索引,就像$runs.0.results
一样。
你需要使用.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"。