LoopBack4 MongoDB Auto Increment custom ID

Viewed 1380

LoopBack itself is new for me and I see version 4 is way too different from version 3. My requirement is that I need to have a custom auto incremented id in my mongoDB document every time I create a POST to the REST end point similar to a running id in a MySQL database.

I did check this (auto-increment using loopback.js and MongoDB) and (https://gist.github.com/drmikecrowe/5a5568930bad567d4148aad75c94de5a) with a version 3 setup, but i did not find proper document to replicate the same on version 4.

Currently I am using a basic app with the out of the box REST implementations provided from the loopback 4. Below is an example of my model.

export class Test extends Entity {
  @property({
   type: 'string',
   id: true,
  })
  _id?: string;

  @property({
   type: 'number',
   generated: true,
   required: false
  })
  id: number;

  @property({
    type: 'string',
    required: true,
  })
  name: string;

  @property({
    type: 'boolean',
    required: true,
  })
  val: boolean;

  constructor(data?: Partial<Test>) {
    super(data);
  }
}

My mongodb document should look something like this:

{
  "_id" : ObjectId("5c373c1168d18c18c4382e00"),  
  "id"  : 1
  "name" : "aaaa",
  "val" : true
}
{
  "_id" : ObjectId("5c3869a55548141c0c27f298"),  
  "id"  : 2
  "name" : "bbbbb",
  "val" : false
}
4 Answers

You can do something like in this example

@post('/characters', {
    responses: {
      '200': {
        description: 'Character model instance',
        content: {'application/json': {schema: {'x-ts-type': Character}}},
      },
    },
  })
  async create(@requestBody() character: Character): Promise<Character> {
    //add following lines
    let characterId = 1;
    while(await this.characterRepository.exists(characterId)){
      characterId ++;
    }
    character.id = characterId;

    //add above lines
    return await this.characterRepository.create(character);
  }

you probably already noticed the auto-increment id feature. When you call the post API multiple times (leave id blank), the id increased by 1 every time. This feature is supported by the in-memory database. But we are using MongoDB in this project. If we want to have that feature, we need to do that programmatically.

For more information follow below link https://strongloop.com/strongblog/building-online-game-with-loopback-4-pt1/

see the section just above the API Explorer heading or find for 'auto increment id' you will be taken to that paragraph

Hopefully, this helps, write me if there is any other query. Thanks

I'm also playing with Mongo and it can autogenerate your id for you.

Specifically, when you create your model, using lb4 model, choosing 'Entity' and then you're prompted:

Let's add a property to Participant
Enter an empty property name when done

? Enter the property name: id
? Property type: string
? Is id the ID property? Yes
? Is id generated automatically? Yes

This will generate your model with the property:

  @property({
    type: 'string',
    id: true,
    generated: true,
  })
  id?: string;

Great.. then when creating your CRUD controller:

? What kind of controller would you like to generate? REST Controller with CRUD functions
? What is the name of the model to use with this CRUD repository? Person
? What is the name of your CRUD repository? PersonRepository
? What is the name of ID property? id
? What is the type of your ID? string
? Is the id omitted when creating a new instance? Yes
? What is the base HTTP path name of the CRUD operations? /persons

Now when hitting your endpoint, the create POST doesn't take an ID, but will return one for you.

You can do something like in this example

let last_record = await this.testRepository.findOne({order: ['id DESC']});
if(last_record) invoice.id = last_record.id+1;

This will generate your model with the property:

@property({
    type: 'number',
    id: true,
    default: 1,
    generated: false
  })
  id: number;

Hopefully, this helps, please write me if there is any other code. Thanks

This class inherits from the DefaultCrudRepository class and overrides the create method. The method uses the "Counters" collection to hold the last id of the current data class (this.entityClass.name). The findAndModify method will prevent duplicate id values from being created.

import {DefaultCrudRepository, Entity, DataObject, Options} from '@loopback/repository';

export class MongoAutoIncIdRepository<T extends Entity, ID, Relations extends object = {}> extends DefaultCrudRepository<T, ID, Relations> {

  public async create(entity: DataObject<T>, options?: Options): Promise<T> {
    if (!this.dataSource.connected) {
      await this.dataSource.connect()
    }
    
    let mongoConnector = this.dataSource.connector!

    let collection = mongoConnector.db.collection('Counters')

    let result = await collection.findAndModify(
      {
        collection: this.entityClass.name
      },
      [['_id', 'asc']],
      {
        $inc: {value: 1}
      },
      {
        upsert: true,
        new: true
      })

    console.log(result)
    // @ts-ignore
    entity.id = result.value.value
    return super.create(entity, options)
  }

}

It's easy to use. Inherit your repository not from DefaultCrudRepository, but from MongoAutoIncIdRepository if auto increment is required. Then, when the create method is called, the id will increase by 1 automatically.

Related