Search code examples
javascriptvalidationjoi

Why does Joi validate an array of objects with "contains a duplicate value"?


My schema is:

const scenerioSchema = Joi.object({
  drawingNode: Joi.object({
    moduleRackOutputs: Joi.array()
      .items(
        Joi.object({
          moduleId: Joi.string().required()
        })
      )
      .unique((a, b) => a.moduleId !== b.moduleId)
  })
})

My data is:

const mockScenario1 = {
  drawingNode: {
    moduleRackOutputs: [
      {
        moduleId: 'module1'
      },
      {
        moduleId: 'module2'
      }
    ]
  }
}

When I validate with:

const validationResponse = scenerioSchema.validate(mockScenario1)

I get:

{
      validationResponse: {
        value: { drawingNode: [Object] },
        error: [Error [ValidationError]: "drawingNode.moduleRackOutputs[1]" contains a duplicate value] {
          _original: [Object],
          details: [Array]
        }
      }
    }

But (a) that's not true - the items are not duplicates and (b) I want an error to occur if the moduleId is different.

What am I doing wrong?


Solution

  • The Solution

    As @Ankh suggested,
    the solution to your problem is to replace the !== with ===.

    Why is this the solution?

    When you did the !==, what you essentially told Joi is:
    "All array elements must have the SAME unique key!" So here are some example data that would pass:

    // Example 1: would pass!
    const arr = [ { moduleId: 0 } ];
    
    // Example 2: would pass!
    const arr = [ { moduleId: 0 } , { moduleId: 0 }]
    
    // Example 3: would pass!
    const arr = [ { moduleId: 0 } , { moduleId: 0 }, { moduleId: 0 }] // and so on...
    

    These following examples, however, would fail:

    // Example 4: would fail...
    const arr = [ { moduleId: 0 }, { moduleId: 1 } ];
    
    // Example 5: would fail...
    const arr = [ { moduleId: 1 } , { moduleId: 2 } , { moduleId: 3 }]
    
    // Example 6: would fail...
    const arr = [ { moduleId: 1 } , { moduleId: 1 } , { moduleId: 2 }]
    

    That is because Joi runs the "unique" validation against all other items in the array, and says: "I'm gonna declare DUPLICATE whenever I see an element j that is !== to element i", and what you want is the exact opposite.