Reputation: 71
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"
}
}
}
Upvotes: 6
Views: 1654
Reputation: 932
Unfortunately this is still not implemented by loopback. Please refer to this issue https://github.com/strongloop/loopback-datasource-juggler/issues/846.
Upvotes: 0
Reputation: 71
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.
Upvotes: 1
Reputation: 2872
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"
Upvotes: 0
Reputation: 1205
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.
Upvotes: 0