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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:10:36