creation of nested documents "all at once": any workarounds?

368 views
Skip to first unread message

Aarti Kumar

unread,
Jul 13, 2017, 6:55:43 PM7/13/17
to LoopbackJS
Hi,

I'm using mongodb and nested documents is a basic database feature.

However, as per loopback documentation on embedded relations, one can't create a nested schema "at once".

So, if I have multiple embedded models, like addresses, multiple emails/phone numbers, etc., it would mean that I would need to call the API as many times for a single create. I don't think this is the best approach as API calls to a remote server should be minimised to the extent possible, esp. on unreliable networks.

Is there any workaround for this at the moment - e.g. Custom remote methods?

Thanks much.
Warm regards,
Aarti

Francois Laforge

unread,
Jul 14, 2017, 11:45:54 AM7/14/17
to LoopbackJS
Unfortunately no.  Loopback, out-of-the-box provides a lot of functionality, but when it comes to the API and "child" relations, you need to create them one at at a time.

I think your only option would be to create a custom end-point (remote method) that accepts an array of values, then you add the array manually in code.  

Example:

ParentModel.createChildren = function(parentId, children, callback){
 
Const ChildModel = ParentModel.app.models.ChildModel
  children
.forEach(child => child.parentId = parentId); // set the parent Id of the children
 
ChildModel.create(children, callback);

 
// not sure if you can create multiple children at the same time for an EmbedsMany
 
// if not, just loop through or use Async and return the result.  Still only 1 API call.
}

ParentModel.remoteMethod('createChildren', {
  accepts
:[
   
{arg:'parentId', type:'string', required: true},
    {arg:'children', type:'array', required: true},
 
],
  http
: {path:'/Parents/:parentId/create-children', verb: 'POST'},
  returns
: {type: 'object', root: true},
});

Mark Johnson

unread,
Jul 14, 2017, 10:07:02 PM7/14/17
to LoopbackJS
We encountered this as well.

While it may not help your situation, I will add that the benefit is that by forcing the use of these additional endpoints you can consistently enforce business logic into the create and update functions for the relation without having to duplicate it within the parent model, especially if used within multiple models.

Otherwise Francois' solution is really your only choice.

Aarti Kumar

unread,
Jul 15, 2017, 12:19:38 PM7/15/17
to LoopbackJS
Thanks so much Francois and Mark! This is very helpful.

I'm a little confused as I experimented with posting a JSON record containing an embedsOne record, using the standard post API through the API explorer, and it seamlessly added it. I'm using loopback 3.x. Not sure if they have recently added this functionality in and not yet updated the documentation? Or am I missing something?

Thanks much!
Warm regards,
Aarti

Francois Laforge

unread,
Aug 9, 2017, 10:47:14 AM8/9/17
to loopb...@googlegroups.com
I just realised a mistake I made for your question:  The "Embeds" relations are different than the "Relates to" relations.

If you are using MongoDb as your database, the embeds many relation saves the child instances in the parent:

parent={
 id
: 1,
 label
: 'my model',
 _children
:[
   
{child 1},
   
{child 2},
   
{child 3}
 
]
}

You can CRUD the child instances using the /ParentModel/{id}/ChildModel/{fk} api end-point, but you can also create your children using  /ParentModel/{id}.  I find this is one one of the major draw-backs of the EmbedsOne and EmbedsMany relation.

In other words, I can create/update/delete multiple child instances of my model with one API call:

// Url
POST
/ParentModel/{id}

// Data
{
  _children
:[
   
{child 3},
   
{child 4},
   
{child 5}
 
]
}

The problem here is that no validation is performed on the child model.  The *.__create__childModel remote method is not called and the Before/After save is not called on the child model.  Used this way Loopback (v2) treats the _children property as any other property and not as an embedded model.

SO, you CAN create multiple embedded models in a single, built-in api call, but the disadvantage is there is no validation performed and your end-user could input anything as a child model.
Reply all
Reply to author
Forward
0 new messages