【问题标题】:Joi: filter values based on other key's valueJoi:根据其他键的值过滤值
【发布时间】:2026-02-08 07:25:01
【问题描述】:

我有一个如下所示的类型列表

const types = ['BAKERY', 'FRUITS', 'RESTAURANT', ...];

这个数组的长度未知。我对上述每种类型都有一个相应的类别列表,如下所述

const categories = {
  RESTAURANT: ['ADDON', 'AMERICAN', 'ANDHRA', ....],
  FRUITS: ['APPLE', 'BANANA', ....],
  RESTAURANT: ['VEG', 'NONVEG', ....],
};

我想根据所选类型验证类别的架构。

const itemJoiSchema = Joi.object({
  type: Joi.string()
    .valid(...enums.types)
    .required(),
  category: Joi.string()
    .valid(............) // Here i want to accept only the values which fall into selected type above
    .uppercase()
    .required()
});

如果我选择type: 'FRUITS',,那么该类别应该只接受['APPLE', 'BANANA', ....], 中的一个,其他类别也是如此。

我尝试使用 refs 但没有奏效。有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: javascript node.js express joi hapi.js


    【解决方案1】:

    如果您不介意使用非 Joi 解决方案,您可以通过键动态访问对象值。

    const categories = {
      BAKERY: ['ADDON', 'AMERICAN', 'ANDHRA', ....],
      FRUITS: ['APPLE', 'BANANA', ....],
      RESTAURANT: ['VEG', 'NONVEG', ....],
    };
    
    const type = "FRUITS";
    
    console.log(categories[type]); // ['APPLE', 'BANANA', ....],
    

    所以你可以这样做:

    // Example data to validate
    const data = {
        type: "FRUITS",
        category: "APPLE"
    };
    
    // enums example:
    const enums = {
        categories: {
            RESTAURANT: ['ADDON', 'AMERICAN', 'ANDHRA', ....],
            FRUITS: ['APPLE', 'BANANA', ....],
            RESTAURANT: ['VEG', 'NONVEG', ....],
        },
        types: ['BAKERY', 'FRUITS', 'RESTAURANT', ...]
    }
    
    const itemJoiSchema = Joi.object({
      type: Joi.string()
        .valid(...enums.types)
        .required(),
      category: Joi.string()
        .valid(...enums.categories[data.type] || []) 
        .uppercase()
        .required()
    });
    

    由于data.type 的值为"FRUITS",它会将categories.FRUITS 作为有效数组传递。结果将等价于这个

    // Example data to validate
    const data = {
        type: "FRUITS",
        category: "APPLE"
    };
    
    const itemJoiSchema = Joi.object({
      type: Joi.string()
        .valid(...enums.types)
        .required(),
      category: Joi.string()
        .valid(...['APPLE', 'BANANA', ....]) 
        .uppercase()
        .required()
    });
    

    注意:|| [] 是为了防止在用户传递不正确的type 时出错。

    工作示例:https://repl.it/repls/SuperAlienatedWorkplace。更改data.type 值,您将看到有效类别值相应更改

    【讨论】:

    • 类型选择可以是任意一种吧?那么您的解决方案如何为类别选择动态值?
    • 是的,它可以是任何东西,例如categories["FRUITS"] 等同于categories.FRUITS。我的答案也有错字,应该是.valid(...enums.categories[data.type] || []) ,而不是.valid(...enums.categories[data.category] || [])。此行是您根据 data.type 值传递有效类别值的位置。
    【解决方案2】:

    你可以尝试使用Joi的.when()方法

    类似

    const itemJoiSchema = Joi.object({
      type: Joi.string()
        .valid(enums.types)
        .required(),
      category: Joi.string()
        .when(type { is: 'FRUIT', then: joi.valid(categories.FRUIT })
        // etc
        .uppercase()
        .required()
    });
    

    【讨论】: