Joi Validations: If object matches the schema validate against it from multiple items
Asked Answered
P

1

7

I am having an array of objects to validate from the specific schemas and if any of the objects matches with the given schemas, I want to validate against it and ignore other schemas and move to next array item.

I tried Joi.alternatives but it will go and check against all the schemas instead of checking only one if it got matched.

My validator:

Joi.array().min(1).max(49).items(Joi.object({
    type: Joi.number().valid([1, 2, 3, 4]).required()
}).when(Joi.object({
    type: Joi.number().valid(1)
}).unknown(), {
    then: profile1
}).when(Joi.object({
    type: Joi.number().valid(2)
}).unknown(), {
    then: profile2
}).when(Joi.object({
    type: Joi.number().valid(3)
}).unknown(), {
    then: profile3
}))

Profile1//type1

export default Joi.object().keys({

    type: Joi.number().valid([1, 2, 3]).required(),
    surname: Joi.string().max(50).allow(""),
    givenname: Joi.string().max(50).allow("")

}).unknown(true)

Profile2//type2

export default Joi.object().keys({

    type: Joi.number().valid([1, 2, 3]).required(),
    address: Joi.string().max(50).allow(""),
    initialname: Joi.string().max(50).allow(""),
    surname: Joi.string().max(50).allow(""),
    data: Joi.array.min(1).max(29).items(Joi.object({
       code: Joi.string().max(20).allow(""),
       number: Joi.string().max(20).allow(""),
    }),
    address1: Joi.array.min(1).max(29).items(Joi.object({
       city: Joi.string().max(20).allow(""),
       postal: Joi.string().max(20).allow(""),
    })
}).unknown(true)

Profile3//type3

export default Joi.object().keys({

    type: Joi.number().valid([1, 2, 3]).required(),
    units: Joi.string().max(50).allow(""),
    others: Joi.string().max(50).allow(""),
    surname: Joi.string().max(50).allow(""),
    data2: Joi.array.min(1).max(29).items(Joi.object({
       sub1: Joi.string().max(20).allow(""),
       sub2: Joi.string().max(20).allow(""),
    }),
    additional: Joi.array.min(1).max(29).items(Joi.object({
       data1: Joi.string().max(20).allow(""),
       data2: Joi.string().max(20).allow(""),
    })

}).unknown(true)
  • If profile1 gets matched how I can only validate that and avoid others
  • Same when I have multiple arrays of objects only validate against the specific profiles

sample object:

[
   {
      "type":1,
      "surname":"",
      "givenname":""
   },
   {
      "type":2,
      "surname":"val",
      "address":"testte",
      "initialname":"test",
      "data":[{
         "code":"test",
         "number":"test"
      }],
      "address1":[{
         "city":"test",
         "postal":123
      }
   }],
   {
      "type":"3",
      "surname":"",
      "units":"",
      "others":"",
      "data2":[{
         "sub1":"test",
         "sub2":"test"
      }],
      "additionals":[{
         "data1":"test",
         "data2":123
      }]
   }
]

here profile1 gets matched with given data so it should validate against it and ignore profile2 and profile3 (also validate type is number)

here profile2 gets matched with given data so it should validate against it and ignore profile1 and profile3 (also validate type is number)

now it should move to the next object from the array where type is not number so it should not check schema and throw an error

Note: I am using Joi version 13.4.0

Pournaras answered 2/12, 2022 at 16:45 Comment(3)
As written, your schemas are not valid code and will not run. Additionally, your schemas have data, data1, address, and additionals marked as arrays of objects and your sample data presents each of those fields as objects alone, meaning even if your code would run, it wouldn't validate anyway. I think if you cleaned up the question a bit, someone could help you.Parmesan
Have you seen this? Adds an alternative schema type for attempting to match against the validated value.Sterner
#77393145Tigges
A
2

There are some typos in your files and validators.

First of Joi.array is a function and needs to be called as one.

// This is incorrect
data2: Joi.array
...
additional: Joi.array

// Should be changed to this where array is invoked as a function
data2: Joi.array()
...
additional: Joi.array()

Additionally, I've added a fourth validator which basically passes all sample objects which have a type greater than 3.

.when(
  Joi.object({
    type: Joi.number().greater(3),
  }).unknown(),
  {
    then: Joi.object().unknown(true),
  }
)

And there are other typos in your validators e.g missing brackets - I created a fixed version of your validator in codesandbox.

Validation is still failing in the codesandbox since in profile2.js postal is declared as string, but in your samples array it is a number for the second object, search for postal: 123 and change it to postal: "123" or modify the validation of postal from postal: Joi.string() to postal: Joi.number()

This way if one of the validators passes then the other ones won't throw an error, and if the type is greater than 3 it will pass validation.

Alb answered 11/12, 2022 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.