Home > Back-end >  mongoose-unique-validator not working with typegoose nested object
mongoose-unique-validator not working with typegoose nested object

Time:10-18

I'm using typegoose nested classes with mongoose-unique-validator as follows

import {
  prop,
  plugin,
  post,
  index,
  getModelForClass,
} from "@typegoose/typegoose";

const uniqueValidator = require("mongoose-unique-validator");

@plugin(uniqueValidator, {
    message: "{VALUE} already exists",
})

// ATTRIBUTES CLASS
class Attributes {
  @prop({
    default: false,
  })
  active: boolean;
}

export class Specie {
  // NAME
  @prop({
    unique: true,
    required: [true, "Name is required"],
  })
  name: string;

  // NESTED ATTRIBUTES CLASS
  @prop({ _id: false, unique: false })   
  attributes?: Attributes;
}

// EXPORT MODEL
export const SpecieModel = getModelForClass(Specie, {
  existingMongoose: mongoose,
  schemaOptions: {
    collection: "species",
    timestamps: true,
    optimisticConcurrency: true,
    toJSON: {
      transform: (obj, ret) => {
        delete ret.__v;
      },
    },
  },
}) as PaginateModel<Specie, typeof Specie>;

When I remove nested object "Attributes" mongoose-unique-validator works fine giving me the name of the duplicate field. but when I use it with nested object "Attributes" & documents with duplicate names, I get

MongoServerError: E11000 duplicate key error collection : collection.species index: name_1 dup key: { name: "somename" }

I want to make use of unique: true functionality of the mongoose.

Am I using the plugin/typegoose nested objects correctly? Why mongoose-unique-validator not working as expected with typegoose nested object?

CodePudding user response:

Based on the error message the problem seems to be that you try to create a unique constraint on data that is already not unique. The issue is that you already have duplicated names. You will need to perform some operations that are compatible with the needs of your project that end with a state that there are no longer duplicates of name.

You may archive names (create another entity and insert all the duplicates into them except one for each duplicate, then remove the inserted records from the original entity), or you may simply remove all duplications of name, leaving any name values to exist once at most, or you can merge the duplications if they are interrelated.

Basically you will need to make sure that your data already meets the unique constraint and only then add the constraint. Such a constraint will not do your work of figuring out how your data needs to be cleaned up (imagine if some software that's unaware of your project's needs just guesstimates how your data is to be cleaned up and acts upon it, causing you data loss), it is a work that you need to do. The constraint, instead of cleaning your existent data will make sure that future operations will not end up with duplicates on name.

CodePudding user response:

From what i can tell mongoose-unique-validator is meant to search the database for each property that has a unique: true option set to throw a custom error before a save operation.

You are applying the plugin to class Attributes, but are expecting the error to be thrown for Specie, which is not a extending class.

TL;DR: you did not apply the plugin to the class Specie where you expected it.

PS: you can globally apply plugins by using mongoose.plugin which will apply a plugin to all schemas for that mongoose instance defined after the mongoose.plugin call.

  • Related