如何使用AJV校验属性值是否存在于对象数组的指定属性集合中?
解决AJV验证属性值是否存在于对象数组指定属性的问题
你当前的核心问题是:AJV的enum关键字无法通过$data直接引用对象数组中所有项的指定属性值集合,导致无效数据校验通过。下面提供两种可行的实现方式:
方案一:自定义AJV关键字(推荐)
通过自定义关键字实现“值是否存在于数组对象指定属性”的验证逻辑,这是最灵活且无需修改原始数据的方式。
代码实现
import Ajv, { ValidateFunction } from "ajv"; const ajv = new Ajv({ $data: true, strict: true }); // 注册自定义验证关键字 ajv.addKeyword({ keyword: "existsInArrayProperty", type: "string", schemaType: "object", validate: function (schema: { arrayPath: string; property: string }, data: string) { // 通过$data路径获取目标数组 const targetArray = this.getData(schema.arrayPath); if (!Array.isArray(targetArray)) return false; // 检查数组中是否存在项的指定属性等于当前值 return targetArray.some(item => item[schema.property] === data); }, errors: true, // 开启错误信息支持 }); // 编写验证Schema const schema = { type: "object", properties: { things: { type: "array", items: { type: "object", properties: { thing_name: { type: "string" }, }, required: ["thing_name"], // 强制每个数组项必须包含thing_name }, }, other: { type: "string", existsInArrayProperty: { arrayPath: "0/things", // $data路径,指向根对象下的things数组 property: "thing_name", // 要匹配的数组项属性名 }, errorMessage: "other的值必须存在于things数组的thing_name列表中", // 自定义错误提示 }, }, required: ["things", "other"], // 强制必填字段 }; // 测试数据 const validData = { things: [{ thing_name: "foo" }, { thing_name: "bar" }], other: "foo", }; const invalidData = { things: [{ thing_name: "foo" }, { thing_name: "bar" }], other: "baz", }; // 编译并执行验证 const validator = ajv.compile(schema); console.log(validator(validData)); // 输出 true console.log(validator(invalidData)); // 输出 false console.log(validator.errors); // 若校验失败,可查看错误详情
方案二:预处理数据+$data引用
如果不想自定义关键字,可以先将数组中的目标属性提取为单独的字符串数组,再通过enum+$data引用该数组。这种方式需要修改输入数据,适合简单场景。
代码实现
import Ajv, { ValidateFunction } from "ajv"; const ajv = new Ajv({ $data: true, strict: true }); // 预处理数据:提取things中的thing_name为单独数组 const preprocessData = (data: any) => ({ ...data, thingNameList: data.things.map((item: any) => item.thing_name), }); // 编写Schema const schema = { type: "object", properties: { things: { type: "array", items: { type: "object", properties: { thing_name: { type: "string" } }, required: ["thing_name"], }, }, thingNameList: { type: "array", items: { type: "string" } }, other: { type: "string", enum: { $data: "0/thingNameList" }, // 引用预处理后的字符串数组 errorMessage: "other的值不在允许的列表中", }, }, required: ["things", "thingNameList", "other"], }; // 测试 const validator = ajv.compile(schema); console.log(validator(preprocessData(validData))); // true console.log(validator(preprocessData(invalidData))); // false
排查技巧
AJV在$data引用无效时默认通过校验,可通过以下方式排查:
- 确保
strict: true已开启,会对无效的$data引用抛出警告 - 安装
ajv-errors插件,配置自定义错误信息,便于定位问题
内容的提问来源于stack exchange,提问作者Luctins
相关产品推荐
相关产品推荐

