Is it possible to make hasMany relations behave like actual properties in LoopBack 4

Tags: ,



I am building an API using LoopBack 4. Is it possible to use relations as if they were actual properties?

The API stores events (e.g. concerts) in the events table in the database and event dates in the event_dates table. I have successfully added a hasMany relation to the Event model and a belongsTo relation to the EventDate model (one Event can have multiple EventDates) using this [1] instructions.

While I can query the dates using eventRepository.dates(eventId), there aren’t available when I request http://localhost:3000/events – How could I achieve this without asking eventRepository.dates(eventId) separately?

On the other hand I would like to POST and PATCH events without posting and patching the event dates separately – Is this possible with a few lines of code?

This is what I need to make the dates field available under /events right now (doesn’t seem to be the right way):

const events = await this.eventRepository.find(filter);
for (let event of events) {
   event.dates = await this.eventRepository.dates(eventId).find()
}

When I want to add a new event, I need to do this:

POST /events
POST /events/:id/event-dates
POST /events/:id/event-dates
...

Please note: I’m looking for solutions that are already available within the LoopBack framework. Implementing these things are not the problem, I just want this as short and maintainable as possible.

[1] https://loopback.io/doc/en/lb4/HasMany-relation.html

Answer

While I can query the dates using eventRepository.dates(eventId), there aren’t available when I request http://localhost:3000/events – How could I achieve this without asking eventRepository.dates(eventId) separately?

We call this feature “inclusion of related models” and unfortunately it’s not implemented yet. You can track the progress here: https://github.com/strongloop/loopback-next/issues/1352

On the other hand I would like to POST and PATCH events without posting and patching the event dates separately – Is this possible with a few lines of code?

If I understand you correctly, you would like to update both Event and EventDate instance via a single REST API call. We don’t support that functionality and to be honest, I am not sure if we ever will.

This is what I need to make the dates field available under /events right now (doesn’t seem to be the right way).

You solutions is vulnerable to what’s known as “SELECT 1+N PROBLEM” (see e.g. What is the “N+1 selects problem” in ORM (Object-Relational Mapping)?). If your Event has N dates, then you make 1+N database queries.

A better solution is to leverage LoopBack’s inq operator:

const eventIds = events.map(e => e.id);
const dates = await this.datesRepository.find({where:{eventId:{inq: eventIds}}});
// copy "dates" entries to relevant "event" items
// by matching "dates[].eventId" against "events[].id"

If the number of queried events is high, then you will need to split eventIds array into smaller chunks and call this.datesRepository.find multiple times.

Anyhow, that’s the gist of what we are going to implement in LoopBack in the near future.

Since you are looking for a solution that’s already implemented in the framework, the code snippets you have posted are pretty much that.



Source: stackoverflow