You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JOI校验when条件中如何访问当前嵌套对象外部的字段?

Joi嵌套对象跨层级引用字段做条件校验的实现方案

问题根因

Joi的.when()方法默认以当前规则所属字段的直接父级对象为起点查找引用字段:

  • 当text/video字段和type同属根级对象时,直接写.when('type', ...)可以在同级找到目标字段,规则正常生效
  • 当text/video被包裹在content对象内部时,直接写.when('type', ...)会尝试查找content.type这个不存在的字段,条件永远无法匹配,因此规则失效

可行实现方案

方案1:指定引用的祖先层级(改动最小,兼容原有写法)

只需要修改.when()的引用路径,明确指定向上查找的祖先层级,即可正确拿到根级的type字段值。推荐用Joi.ref的ancestor参数明确层级,避免手写相对路径出错:

const schema = Joi.object({
    type: Joi.string().valid("text", "video").required(),
    content: Joi.object().keys({
        text: Joi.object().keys({
            body: Joi.string().required(),
            preview_url: Joi.boolean().required()
        }).when(Joi.ref('type', { ancestor: 2 }), {
            is: "text",
            then: Joi.required(),
            otherwise: Joi.forbidden()
        }),

        video: Joi.object().keys({
            url: Joi.string().required()
        }).when(Joi.ref('type', { ancestor: 2 }), {
            is: "video",
            then: Joi.required(),
            otherwise: Joi.forbidden()
        })
    })
})

参数说明:ancestor: 2代表从当前text/video字段出发,向上回溯2级祖先:第1级是父对象content,第2级是根校验对象,最终取根对象上的type字段做条件判断。


方案2:父级对象统一配置条件规则(逻辑更易维护)

把条件判断逻辑上移到content对象的规则层,不需要在子字段中跨多层引用,后续调整规则时更集中,不容易出路径错误:

const schema = Joi.object({
    type: Joi.string().valid("text", "video").required(),
    content: Joi.object().keys({
        text: Joi.object().keys({
            body: Joi.string().required(),
            preview_url: Joi.boolean().required()
        }),
        video: Joi.object().keys({
            url: Joi.string().required()
        })
    }).when(Joi.ref('type', { ancestor: 1 }), {
        switch: [
            {
                is: "text",
                then: Joi.object({ text: Joi.required() }).unknown(true),
                otherwise: Joi.object({ text: Joi.forbidden() })
            },
            {
                is: "video",
                then: Joi.object({ video: Joi.required() }).unknown(true),
                otherwise: Joi.object({ video: Joi.forbidden() })
            }
        ]
    })
})

参数说明:content的直接父级就是根对象,因此ancestor: 1即可拿到根级type值;通过switch分支匹配不同type值的规则,.unknown(true)用于保证content下其他已定义的字段不会被判定为非法字段。


校验效果

两种方案都可以完全满足需求:

  • 当type值为text时,content.text为必填项,content.video禁止传入
  • 当type值为video时,content.video为必填项,content.text禁止传入
  • 校验行为和同级平铺的生效规则完全一致

内容的提问来源于stack exchange,提问作者turivishal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:18:18