Loopback-next: Possible bug inside findOne with MongoDB

Created on 2 Apr 2019  路  16Comments  路  Source: strongloop/loopback-next

Description / Steps to reproduce / Feature proposal

I have only 2 models test and atest
test has (id,name,age)
atest has (testId) which refers to the id from test model

I have only 1 controller for (atest) with 2 ENDPOINTS
get '/eltest' > which findOne by the testId

return await this.atestRepository.findOne({where : {testId : "5ca358720916cec7fd29e875"}});

get '/anothertest' > which findOne by the id

return await this.atestRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}});

Current Behavior

the first one works well - but the second one not find the exist record

Expected Behavior

both should work and find the exist record inside the database

Searches and solutions I tried with

changing @model() to @model({ settings: { strictObjectIDCoercion: true, }, }) inside atest model ;
works like a switch - it damage the working ENDPOINT and fix the damaged ENDPOINT

please use this repo to reproduce the issue

Relations MongoDB

Most helpful comment

You need to use 2 different repository for this case. See here
return await this.atestRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}});

atest model doesn't have an id column as you shared earlier. So it cannot search by id on that. Even if it had, that should correspond to id field in atest model. It can never be test model id. I think what you intend to do is

return await this.testRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}});

Note I am using testRepository here. That should work.

BTW, I think stack overflow is a better place for raising such queries.

All 16 comments

You need to use 2 different repository for this case. See here
return await this.atestRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}});

atest model doesn't have an id column as you shared earlier. So it cannot search by id on that. Even if it had, that should correspond to id field in atest model. It can never be test model id. I think what you intend to do is

return await this.testRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}});

Note I am using testRepository here. That should work.

BTW, I think stack overflow is a better place for raising such queries.

@samarpanB

yes I noted that you used return await this.testRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}}); , but that's not what I need , I need to use this return await this.atestRepository.findOne({where : {id : "5ca3589e0916cec7fd29e87a"}}); in my logic = I need to call it with atest repo

@dhmlau @bajtos , can you please check this issue because it does not make our project workable?

@b-admike , could you please take a look? thanks.

I think this is related to the pull requests that @hacksparrow is working on now, see https://github.com/strongloop/loopback-connector-mongodb/pull/517 and https://github.com/strongloop/loopback-connector-mongodb/pull/525

@hacksparrow, is this issue resolved since the two above PRs had landed?

ObjectID strings behave in a predictable manner now, in loopback-connector-mongodb 5.x.

There is a crucial missing piece in the example app provided by @frodoe7 - the creation aspect of the models. We don't know how the models are populated in the databases.

@frodoe7 also, the property name should be mongodb, not mongo.

FWIW, while playing with relations, I discovered an important limitation of the current solution based on juggler v4 and mongodb connector: when the primary key (id property) is configured as generated: true, juggler always rewrites its type to ObjectID, regardless of the type specified in LB4 property definition. See https://github.com/strongloop/loopback-datasource-juggler/blob/0c2bb81dace3592ecde8b9eccbd70d589da44d7d/lib/datasource.js#L713-L719

An example model definition that's affected:

@model()
class MyModel extends Entity {
  @property({
    type: 'string',
    id: true,
    generated: true,
  })
  id: string;
}

I am not sure yet whether this is a problem and how to address it if it is a problem.

Hello,
we have the same crucial problem.
FindOne works well with strings until they match a perfect ObjectID string.
In this specific case it fail.

As an example, the following works:
const customer = await this.customerRepository.findOne({ where: { digitalUserId: '5d385199e9b4c12fe02612a' }, });

The following not work:
const customer = await this.customerRepository.findOne({ where: { digitalUserId: '5d385199e9b4c12fe02612a5' }, });

Is there a possible workaround?
I've downloaded loopback-mongodb-connector v.5.0.0 but the problem persists.

Thank you.

@UnclePetros what is the property digitalUserId defined as? Can you share it?

@hacksparrow digitalUserId has this definition in the Customer model:

@property({ type: 'string', }) digitalUserId?: string;

I use a mongodb datasource.

Unfortunately I've tried to reproduce it in the todo-list example, but without success.
Anyway, I've noticed if I save the digitalUserId as an ObjectIdin the mongodb database then the findOne works fine.

@UnclePetros that's correct loopback-mongodb-connector 5.0 onwards, properties should be set as ObjectId, if they are to be treated as one; and autogenerated ids are ObjectIds.

@hacksparrow ok, very interesting this new feature.
I'll upgrade the code in order to use it.

@hacksparrow @UnclePetros, is this ticket good to close then? Thanks.

Hello, yes of course.
Thank you again.

Closing as done.

Was this page helpful?
0 / 5 - 0 ratings