Page Contents

Overview

A hasOne relation sets up a one-to-one connection with another model, such that each instance of the declaring model “has one” instance of the other model. A hasOne relation is a degenerate case of a hasMany relation.

Defining a hasOne relation

Use the relation generator to create a relation between two models. The tool will prompt you to enter the name of the model, the name of related model, and other required information. The tool will then modify the model definition JSON file (for example, common/models/customer.json) accordingly.

For example, consider two models: supplier and account.

common/models/supplier.json

{
  "name": "supplier",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "name": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {
    "supplier_acct": {
      "type": "hasOne",
      "model": "account",
      "foreignKey": "supplierId",
      "primaryKey": "id" // optional
    }
  },
  "acls": [],
  "methods": []
}

A supplier has one account, where the foreign  key is on the target model: account.supplierId -> supplier.id.

common/models/account.json

{
  "name": "account",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "id": {
      "type": "number",
      "required": true
    },
    "acctmgr": {
      "type": "string"
    },
    "supplierId": {
      "type": "number",
      "required": true
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}

Alternatively, you can define a “hasOne” relation in code, though in general this is not recommended:

common/models/supplier.js

Supplier.hasOne(Account, {foreignKey: 'supplierId', as: 'account'});

If the target model doesn’t have a foreign key property, LoopBack will add a property with the same name. The type of the property will be the same as the type of the declaring model’s id property. Please note the foreign key property is defined on the target model (for example, Account).

If you don’t specify them, then LoopBack derives the relation name and foreign key as follows:

  • Relation name: Camel case of the model name, for example, for the “supplier” model the relation is “supplier”.
  • Foreign key: The relation name appended with Id, for example, for relation name “supplier” the default foreign key is “supplierId”.

Methods added to the model

Once you define the hasOne relation, LoopBack automatically adds a method with the relation name to the declaring model class’s prototype. For example: supplier.prototype.account(...).

The relation can return a promise by calling the get() method on the relation property.

Example method Description
supplier.account(function(err, account) {
...
});

Find the supplier's account model.

REVIEW COMMENT from Rand
You cannot supply a filter, as you can for hasMany right?

var supplier = supplier.account.build(data);

Or equivalently:

var account = new account({supplierId: supplier.id, ...});
Build a new account for the supplier with the supplierId to be set to the id of the supplier. No persistence is involved.
supplier.account.create(data, function(err, account) {
...
});

Or, equivalently:

account.create({supplierId: supplier.id, ...}, function(err, account) {
...
});
Create a new account for the supplier. If there is already an account, an error will be reported.
supplier.account.destroy(function(err) {
...
});
Remove the account for the supplier.
supplier.account.update({balance: 100}, function(err, account) {
...
});
Update the associated account.
supplier.account.get().then(function(account) { ... });
Use the `get()` method on the relation name to return a promise.