loopback save related hasmany models in single request
Asked Answered
D

4

6

I have two models that are related through a hasMany relationship.

Customer hasMany CustomerPhones

When creating a new Customer, I would like to pass the related CustomerPhones as part a single request. This seems like a common need, if the approach I am looking to implement in wrong, what is the preferred way of doing this?

This is the url for creating a customer: POST /api/Customers

The request for above url would be req.body

{
  "name": "Foo",
  "customerPhones": [
    { "phoneNumber": "8085551234" },
    { "phoneNumber": "8085554567" }
  ]
}

Loopback models configurations:

Customer.json

{
  "name": "Customer",
  "base": "User",
  "properties": {
    "name": {
      "type": "string",
      "required": true
    }
  },
  "relations": {
    "customerPhones": {
      "type": "hasMany",
      "model": "CustomerPhone",
      "foreignKey": ""
    }
  }
}

CustomerPhone.json

{
  "name": "CustomerPhone",
  "base": "PersistedModel",
  "properties": {
    "phoneNumber": {
      "type": "string",
      "required": true
    },
    "customerId": {
      "type": "number",
      "required": true
    }
  },
  "relations": {
    "customer": {
      "type": "belongsTo",
      "model": "Customer",
      "foreignKey": "customerId"
    }
  }
}
Dietrich answered 4/12, 2015 at 21:12 Comment(0)
D
1

I am not sure if this is the best solution, but here it what I ended up doing. I created a new RemoteMethod named createNew on Customer. Within this new remote method I use the methods added through the model relationships.

Customer.createNew = function (data) {
  var newCustomerId;
  var customerPhones = null;

  if (data.customerPhones && data.customerPhones.length) {
    customerPhones = data.customerPhones;
  }

  return Customer
    .create(data)
    .then(function createCustomerPhones (customer) {
      newCustomerId = customer.id;
      if (customerPhones) {
        customer.customerPhones.create(customerPhones);
      }
    })
    .then(function fetchNewCustomerIncludeRelated () {
      return Customer
        .findById(newCustomerId, {
          include: [ 'customerPhones' ]
        });
    })
    .catch(function (err) {
      return err;
    });
};

To make this a bit safer I will need to wrap it in a transaction. I was hoping to use the base CRUD methods, but this solution if fairly clean.

Dietrich answered 7/12, 2015 at 9:26 Comment(0)
S
0

If you are using NoSQL database connector, then you could ignore another CustomerPhone model and add the customerPhones property as an array in the Customer model.

Else for SQL database connector, you could create a remote method that performs both POST /api/Customers and POST /api/Customers/id/CustomerPhones together. For multiple phone numbers you could iterate the customerPhones field in the req.body and perform POST /api/Customers/id/CustomerPhones everytime.

Stylus answered 5/12, 2015 at 11:27 Comment(2)
I am using SQL. What you are suggesting is what I basically ended up doing. I made a new RemoteMethod named create.Dietrich
I think there is no other way of doing this as CustomerPhones is dependent on the Customer object for the belongsTo relation to work.Stylus
S
0

If this could be any help, instead of iterating you can insert the numbers in a single step like this:

curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" -d "[{
        \"number\": \"1000\",
        \"type\": \"mobile\",
        \"customerId\": 1
    }, {
        \"number\": \"1004\",
        \"type\": \"home\",
        \"customerId\": 1
    }, {
        \"number\": \"1400\",
        \"type\": \"work\",
        \"customerId\": 1
    }]" "http://127.0.0.1:3000/api/customers/1/phones"
Sorrento answered 5/12, 2015 at 17:42 Comment(3)
I am wanting to basically create a new Customer and new Phones in the same call. Because the Customer does not yet exist I can not use Customer/:id/Phones. The customerId is not know yet.Dietrich
Down voted as it says it wants to create customer & phones in one requestValonia
@Anoop.P.A wake up due and read question again.It says it wants to do 2 data entries in 1 request.And in your answer ,customer data entry is already done and you are updating it with second request.So yours is wrong answerValonia
H
0

Unfortunately this is still not implemented by loopback. Please refer to this issue https://github.com/strongloop/loopback-datasource-juggler/issues/846.

Hardhearted answered 23/10, 2017 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.