Model that hasAndBelongsTo the same Model

1,673 views
Skip to first unread message

Julian Mayorga

unread,
Jun 11, 2014, 10:18:04 AM6/11/14
to loopb...@googlegroups.com
First of all I want to say thanks to everyone that supports Loopback, it's a pleasure to scaffold with Loopback robust, authenticated and documented APIs in node.js.

I have a question: How do you define in models.json that a Model has many instances of the same Model? e.g. I have an Organization model, and an Organization can have many Organizations as clients.

I tried to define a hasMany thorugh relationship, but it didn't work. For more details about my models.json that did not work take a look at my StackOverflow question http://stackoverflow.com/questions/24165151/how-to-define-that-a-model-has-many-of-the-same-model-in-strongloop-loopback.

Thanks so much in advance,
Julián Mayorga.
Message has been deleted

Lee Driscoll

unread,
Jun 11, 2014, 10:29:42 AM6/11/14
to loopb...@googlegroups.com
I haven't tried this personally, but I recommend removing the properties from your client model as Loopback will automatically create these from the foreign keys in the relation configs

Julian Mayorga

unread,
Jun 11, 2014, 11:44:18 AM6/11/14
to loopb...@googlegroups.com
Lee, I tried your suggestion but unfortunately it did not work.

I also tried defining the relationship in code as exemplified in the official docs http://docs.strongloop.com/display/DOC/Creating+model+relations#Creatingmodelrelations-hasManyThrough. Unfortunately I could not find anywhere how to make this relationship work using the same Model instead of two different ones. I ended up with the following code that also did not work:

  var loopback = require('loopback');                                      
  var app = require('../app');                                             
  var Organization = app.models.organization;                              
  var Client = app.models.client;                                          
      
  Client.belongsTo(Organization);                                          
        
  Organization.hasMany(Organization, {through: Client});

My models.json looks like this now:

"organization": {
    "properties": {
      "name": {
        "type": "string"
      }
    },
    "relations": {
      "users": {
        "type": "hasMany",
        "model": "user",
        "foreignKey": "organizationId"
      }
    },
    "dataSource": "mongodb",
    "public": true,
    "plural": "organizations"
  },
  "client": {
    "properties": {
      "organizationId": {
        "type": "number",
        "id": true
      },
  "clientId": {
        "type": "number",
        "id": true
      }
    },
    "dataSource": "mongodb",
    "public": true,
    "plural": "clients"
  }

Any kind of help to guide me in the right direction will be greatly appreciated.

Regards,
Julián.

Lee Driscoll

unread,
Jun 11, 2014, 11:57:28 AM6/11/14
to loopb...@googlegroups.com
Still not sure about how to go through the Client model, but for having an Organization that can have many Organizations, the following works (just tested):

"organization": {
       
"properties": {
           
"name": {
               
"type": "string"
           
}
       
},

       
"options": {
           
"relations": {
               
"organizations": {
                   
"type": "hasMany",
                   
"model": "organization",
                   
"foreignKey": "organizationId"
               
},
               
"organization": {
                   
"type": "belongsTo",
                   
"model": "organization",

                   
"foreignKey": "organizationId"
               
}
           
}
       
},
       
"dataSource": "mongodb",
       
"public": true,
       
"plural": "organizations"
   
},

Remember that the relations object needs to be inside the options object

Raymond Feng

unread,
Jun 11, 2014, 12:02:41 PM6/11/14
to Lee Driscoll, loopb...@googlegroups.com
Lee, you are right. Your example shows how to set up a hasMany/belongsTo relation to itself.

Thanks,

---
Raymond Feng
Co-Founder and Architect @ StrongLoop, Inc.

StrongLoop makes it easy to develop APIs in Node, plus get DevOps capabilities like monitoring, debugging and clustering.

--
You received this message because you are subscribed to the Google Groups "LoopbackJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to loopbackjs+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Julian Mayorga

unread,
Jun 11, 2014, 12:14:40 PM6/11/14
to Raymond Feng, Lee Driscoll, loopb...@googlegroups.com
That worked perfectly Lee, I am truly grateful. I did not know about the options object, thanks for pointing that out.

Many thanks for your time!

Julián.


--
You received this message because you are subscribed to a topic in the Google Groups "LoopbackJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/loopbackjs/H7ivcbLAaHo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to loopbackjs+...@googlegroups.com.

Lee Driscoll

unread,
Jun 11, 2014, 12:17:06 PM6/11/14
to loopb...@googlegroups.com, ray...@strongloop.com, lsdri...@gmail.com
No worries Juli án, I got to learn something too ;)

Raymond Feng

unread,
Jun 11, 2014, 2:59:29 PM6/11/14
to Julian Mayorga, loopb...@googlegroups.com
To really use a through model to relate to itself is a bit tricky. The following code works for me:

var loopback = require('loopback');
  var app = require('../app');
  var Organization = app.models.organization;
  var Client = app.models.client;

  Client.belongsTo(Organization, {as: 'client', foreignKey: 'clientId'});
  Client.belongsTo(Organization, {as: 'organization', foreignKey: 'organizationId'});

  Organization.hasMany(Organization, {through: Client, foreignKey: 'clientId'});

  Organization.create({name: 'marketing'}, function(err, org1) {
    org1.organizations.create({name: 'sales'}, function(err, org2) {
      Organization.find(function(err, orgs) {
        console.log('Organizations: %j', orgs);
      });
      Client.find(function(err, clients) {
        console.log('Clients: %j', clients);
      });
    });
  });

"organization": {
    "properties": {
      "name": {
        "type": "string"
      }
    },
    "relations": {
      "users": {
        "type": "hasMany",
        "model": "user",
        "foreignKey": "organizationId"
      }
    },
    "dataSource": "db",
    "public": true,
    "plural": "organizations"
  },
  "client": {
    "properties": {
      "organizationId": {
        "type": "number"
      },
  "clientId": {
        "type": "number"
      }
    },
    "dataSource": "db",
    "public": true,
    "plural": "clients"
  }

Thanks,

---
Raymond Feng
Co-Founder and Architect @ StrongLoop, Inc.

StrongLoop makes it easy to develop APIs in Node, plus get DevOps capabilities like monitoring, debugging and clustering.

Jonathan Casarrubias

unread,
Dec 21, 2014, 11:30:06 PM12/21/14
to loopb...@googlegroups.com, mayorga...@gmail.com
Hello Raymond,

I have been trying to use your example but I'm unable to success, I hope you can help me get this through..

Case:
In my project, there are accounts that can sponsorship other accounts, so I need a relation Many to Many Through

I have 2 models

Account and AccountSponsor (Middle Model) and I have been trying using:

================== Boot Script =========================
var loopback = require('loopback');

module.exports = function(app) {

    var
    Account        = app.models.Account,
    AccountSponsor = app.models.AccountSponsor;
    
    AccountSponsor.belongsTo(Account, {as: 'sponsored', foreignKey: 'sponsoredId'});
    AccountSponsor.belongsTo(Account, {as: 'sponsor',   foreignKey: 'sponsorId'  });

    Account.hasMany(Account, {as: 'sponsored', through: AccountSponsor, foreignKey: 'sponsoredId'});
    Account.hasMany(Account, {as: 'sponsors',  through: AccountSponsor, foreignKey: 'sponsorId'});
   
    Account.create({
            "fullName" : "sponsored",
            "username" : "sponsored",
            "email"    : "spon...@sponsored.com",
            "password" : "sponsored"
    }, function(err, account){
   account.sponsors.create({
"fullName" : "sponsor",
"username" : "sponsor",
"email"    : "spo...@sponsor.com",
"password" : "sponsor"
}, function(err, response){
       console.log("SPONSOR: ", response);
});
});
};
=========================

But the relation is being incorrectly created

{
    "_id": {
        "$oid": "54979d81237056d6c0030936"
    },
    "sponsoredId": {
        "$oid": "54979d81237056d6c0030935"
    },
    "sponsorId": null
}

Both Accounts where created in the database but only 1 id is stored in the relation model. I tried using the CLI loopback:relation and I get the exact same error

I appreciate your help and support

John 
Reply all
Reply to author
Forward
0 new messages