Loopback: method findOrCreate strange behaviour

Created on 13 Sep 2016  路  14Comments  路  Source: strongloop/loopback

Hello,

I'm trying to create default users with mapping role in boot script, and i have a strange behaviour with findOrCreate method, it seems not recognized where filter
here's my boot script code:

module.exports = function(app) {
  var Role          = app.models.Role,
      RoleMapping   = app.models.RoleMapping,
      Account       = app.models.Account; // base User
  var users = [{
      username: 'fky',
      email: '[email protected]',
      password: 'xxxx',
    }, {
      username: 'jordi',
      email: '[email protected]',
      password: 'xxxx'
    }, {
      username: 'romain',
      email: '[email protected]',
      password: 'xxxx'
    }];

  users.forEach(function (user, index) {
    Account.findOrCreate({where: {email: user.email}}, user, function(err, account) {
        if (err) throw err;
        console.log('Cr茅ation du compte pour ', account.username)
        Role.findOrCreate({where:{name: 'developpers'}}, {
          name: 'developpers',
          description: "D茅veloppeur de l'application"
        },
        function(err, role) {
          if (err) throw err;
          console.log('Cr茅ation du r么le developpers pour ', account.username);
          role.principals.create({
            principalType: RoleMapping.USER,
            principalId: account.id
          }, function(err, principal) {
            if (err) throw err;
            console.log('Mapping r么le effectu茅 pour ', account.username);
          });
        });
      });
  });
};

Then i look at my mongo database i've got my three accounts but i've got also three roles
maybe i made a mistake but i will had only one role register in database. ?!?
So I'm made a test in a simple loop on another boot script

module.exports = function(app) {
  var Role  = app.models.Role;
      for (var i = 0; i < 3; i++) {
        Role.findOrCreate({where:{name: 'developpers'}}, {
          name: 'developpers',
          description: "D茅veloppeur de l'application"
        }, function (err, role) {
            if (err) throw err;
            console.log('created role : ', role.name);
        });
      }
};

Then i register the same things three time, it is the normal behaviour of findOrCreate method?
as documentation says:
Finds one instance matching the filter object provided as the first parameter. If found, returns the object. If not found, creates a new instance (record).

franckysolo

triaging

Most helpful comment

Sorry for my english!
this is the first loopback project i'm working on my local machine, before i've meet the issue with my tests!
I've made the project with slc:loopback, this was the same script on the boot than sandbox example
difference could be the use of es6 in the first project and not in the sandbox
i had the package json of in bin directory
I hope my explanation is more clear :)

All 14 comments

I may be wrong but your loop must be running faster than your database could commit the insert. Therefore, your subsequent find is failing and it is creating a second entry.

You can factor a delay in your loop to confirm this behaviour.

Can you provide a sample for us to reproduce the issue? See https://github.com/strongloop/loopback/wiki/Reporting-issues#bug-report

@superkhau
hello, here's the fork with some notes
the boot script is in server/boot directory
another test boot script is on bin directory
I've not have the same behaviour on local work and with the loopback-sandbox
I'am using the same sample script

franckysolo

@jannyHou Can you try to reproduce this?

I don't know if i made something wrong or not?

@jannyHou :
hello i've made some other tests with async and promise same result, maybe it could help?

@franckysolo Really appreciate your sandbox, and I can get Error message when I run node . in /loopback-sandbox

I've not have the same behaviour on local work and with the loopback-sandbox

Could you clarify what's the difference between local work and with the loopback-sandbox?

@jannyHou
Hello,
here the result of the console.log when i run npm start (node .) from local work

Account created for  jerry
Account created for  tom
Developpers role created for  tom
Account created for  mickey
Developpers role created for  jerry
Mapping role for  jerry
Developpers role created for  mickey
Mapping role for  tom
Mapping role for  mickey

Entries are not registered in the same order
I've no Error thrown
I've got 3 records from Role developpers

In the sandbox example:
The result of the console.log
Result of console log :

Account created for  tom
Account created for  mickey
Account created for  jerry
Developpers role created for  mickey
Mapping role for  mickey

/home/franckysolo/workatom/loopback-sandbox/node_modules/mongodb/lib/utils.js:98
    process.nextTick(function() { throw err; });
                                  ^
ValidationError: The `Role` instance is not valid. Details: `name` already exists (value: "developpers").

I've add a README.md in bin directory you can see the result of the log scripts tests

@franckysolo Sorry I didn't put it clear, I didn't mean what's the difference between Results, I mean "What is local work? How can I run from local work?"

I assume "run from sandbox" means I git clone sandbox and npm install, then node . 馃槃
Then what do you mean by "run from local work?"

Sorry for my english!
this is the first loopback project i'm working on my local machine, before i've meet the issue with my tests!
I've made the project with slc:loopback, this was the same script on the boot than sandbox example
difference could be the use of es6 in the first project and not in the sandbox
i had the package json of in bin directory
I hope my explanation is more clear :)

@franckysolo When I test with your sandbox, there is only one result in my mongodb collection:

> db.Role.find().pretty()
{
    "_id" : ObjectId("57dc55eca42dd83004ffbbb8"),
    "name" : "developpers",
    "description" : "You are developpers",
    "created" : ISODate("2016-09-16T20:28:28.510Z"),
    "modified" : ISODate("2016-09-16T20:28:28.510Z")
}

And from the console result I can see, I agree with the explanation: https://github.com/strongloop/loopback/issues/2740#issuecomment-246729864

Result:

Create account for  mickey
Confirm creation  true
Create account for  tom
Confirm creation  true
Create account for  jerry
Confirm creation  true
Create role  developpers
Confirm creation  true
Error ValidationError: The `Role` instance is not valid. Details: `name` already exists (value: "developpers").
Error ValidationError: The `Role` instance is not valid. Details: `name` already exists (value: "developpers").

ok thanks
so, it's normal behaviour or not?
Normally, i would not have an error raised at 2nd item, it would return an instance of the existing role instead. Or i can't use a basic loop with findOrCreate with mongo cause of find result delay.
What can i do to overcome this issue, is there an alternative or specific configuration in mongodb or loopback-connector?

@franckysolo I think that's how the async works, I would suggest you to create the role first then in the callback function loop the users and assign them to the role.

@jannyHou : this is exactly what i do :)
thanks

Was this page helpful?
0 / 5 - 0 ratings