Search code examples
loopback4

enforcing uniqueness in loopback4 model's properties


I started to run a simple hello world project using lb4. I created a basic mongodb datasource, and a repository and a simple model (username, password and id) for users with cli command provided by loopback. I also created a user controller, with a built in crud choice provided by loopback.
as you may know, this is a very basic setup but if anyone needs details, I will provide, just comment.
the problem is that, when I try to make new users using explorer, I encounter with duplicate same username models. means that:

{
"_id" : ObjectId("5def4581f7f9d508b0da2d4c"),
"username" : "string",
"password" : "string"
}

and:

{
"_id" : ObjectId("5def4584f7f9d508b0da2d4d"),
"username" : "string",
"password" : "string"
}

the client should enter unique username for signup. that's obvious.
how can I specify uniqueness of a property of a model in loopback 4 (without declaring it as id)?


Solution

  • Due to this issue on github, lb4 already checks for duplicates inside of its context using indexes and 11000 error code of mongoDB (I am talking about shopping example, not a simple lb4 app so BE AWARE! If you want you can implement uniqueness using description below). What I forgot to do was database migration 🐱‍🏍.
    you can do database migration with this command:
    npm run migrate
    so the complete answer should be like this:
    1- inside the model add this: (change uniqueEmail and email to property name you want to be unique)

    @model({
        settings: {
            indexes: {
              uniqueEmail: {
                keys: {
                  email: 1,
                },
                options: {
                  unique: true,
                },
             },
        },
      },
    })
    

    2- check inside of the controller, the endpoint you want to check uniqueness, and add a try catch to catch error of uniqueness which came from your mongoDB datasource:

    try {
      // In my case create the new user, but can be anything you want
      const savedUser = await this.userRepository.create(
        _.omit(newUserRequest, 'password'),
      );
    
      // do stuff and return
    
    } catch (error) {
      // MongoError 11000 duplicate key
      if (error.code === 11000 && error.errmsg.includes('index: uniqueEmail')) {
        throw new HttpErrors.Conflict('Email value is already taken');
      } else {
        throw error;
      }
    }
    

    3- run npm run migrate

    This answer now is a general answer which can be used for any property of any model. Hope this helps.