loopbackio / loopback-next

LoopBack makes it easy to build modern API applications that require complex integrations.
https://loopback.io
Other
4.95k stars 1.07k forks source link

Feature request: navigate through different model #3499

Closed godartm closed 3 years ago

godartm commented 5 years ago

Hi ,

Suggestion

Add the possibility to get a model trought different model based on primary key.

Use Cases

Lets imagine i have model foo , bar , baz and all have an ID as primary key.

foo have a relation with bar, bar have a relation with baz.

How can i retrieve baz from foo ?

Actually i can do

Examples

It should be possible to do :

 fooRepository.bar(id).baz(id)

Acceptance criteria

TBD - will be filled by the team.

nabdelgadir commented 5 years ago

@godartm Let's say you have

Foo: {id: 1, name: 'foo 1'}

Bar: {id: 1, name: 'bar 1', fooId: 1} {id: 2, name: 'bar 2', fooId: 1}

Baz: {id: 1, name: 'baz 1', barId: 1} {id: 2, name: 'baz 2', barId: 2} {id: 3, name: 'baz 3', barId: 1}

Just so I understand this issue correctly, what's your desired outcome when you do something like fooRepository.bar(1).baz(1)? Because fooRepository.bar(1).find() would return:

[{id: 1, name: 'bar 1', fooId: 1},
{id: 2, name: 'bar 1', fooId: 1}]

So when you do fooRepository.bar(1).baz(1), should it return the following?

[{id: 1, name: 'baz 1', barId: 1},
{id: 3, name: 'baz 3', barId: 1}]
godartm commented 5 years ago

Yes you understand right the issue =)

nabdelgadir commented 5 years ago

@godartm Thanks! LoopBack doesn't currently have a way to do this directly, so I created a custom controller class as an example:

import {Filter, repository} from '@loopback/repository';
import {get, getModelSchemaRef, param} from '@loopback/rest';
import {Child} from '../models';
import {GrandparentRepository, ParentRepository} from '../repositories';

export class GrandparentChildController {
  constructor(
    @repository(GrandparentRepository)
    protected grandparentRepository: GrandparentRepository,
    @repository(ParentRepository)
    protected parentRepository: ParentRepository,
  ) {}

  @get('/grandparents/{gid}/{pid}/children', {
    responses: {
      '200': {
        description: "Array of Children belonging to Grandparent",
        content: {
          'application/json': {
            schema: {type: 'array', items: getModelSchemaRef(Child)},
          },
        },
      },
    },
  })
  async find(
    @param.path.number('gid') gid: number,
    @param.path.number('pid') pid: number,
    @param.query.object('filter') filter?: Filter<Child>,
  ): Promise<Child[]> {
    const parents = await this.grandparentRepository.parents(gid).find();
    const parentIds = parents.map(p => p.id);

    const children: Child[] = [];
    const parentsChildren = await this.parentRepository
      .children(pid)
      .find(filter);

    parentsChildren.forEach(child => {
      if (
        !children.some(c => child.id === c.id) && // check duplicates
        parentIds.includes(child.parentId)  // make sure it's the child of a parent of the specified grandparent
      ) {
        children.push(child);
      }
    });

    return children;
  }
}

In this case Foo = Grandparent, Bar = Parent, and Baz = Child.

I'm sure there's a way to make this more efficient, but this is just something to go off of. Please let me know if you have any other questions.

godartm commented 5 years ago

Thanks for the reply , and thanks for the exemple. =)

I can be good to request a feature about this and update the doc to explain how to do this use case.

nabdelgadir commented 5 years ago

You can update the current issue description with the fields from the Feature request template or open a new issue and close this one. 😄

godartm commented 5 years ago

@nabdelgadir i have updated this issue, can you add the "Feature" label please =)

stale[bot] commented 4 years ago

This issue has been marked stale because it has not seen activity within six months. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository. This issue will be closed within 30 days of being stale.

stale[bot] commented 3 years ago

This issue has been marked stale because it has not seen activity within six months. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository. This issue will be closed within 30 days of being stale.

stale[bot] commented 3 years ago

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.