Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loopback 4 filters not working with multiple relations #4644

Closed
pratikjaiswal15 opened this issue Feb 13, 2020 · 8 comments
Closed

Loopback 4 filters not working with multiple relations #4644

pratikjaiswal15 opened this issue Feb 13, 2020 · 8 comments
Assignees

Comments

@pratikjaiswal15
Copy link

pratikjaiswal15 commented Feb 13, 2020

I am using multiple relations in loopback 4. I have 4 models.

User has many carts accessible on url users/user_id/carts
cart has many products. Relation named product
Product has many stocks and product-prices named stocks and productPrices respectively.
Here is a controller at url users/user_id/carts/prices which performs multiple relations as shown below.

get('/users/{id}/carts/prices', {
        responses: {
          '200': {
            description: 'Array of Cart\'s belonging to Users',
            content: {
              'application/json': {
                schema: { type: 'array', items: getModelSchemaRef(Cart) },
              },
            },
          },
        },
      })
      async Multiple_relation(
        @param.path.number('id') id: number,
        @param.query.object('filter') filter?: Filter<Cart>,
      ): Promise<Cart[]> {
        return this.usersRepository.carts(id).find({
          include: [{
            relation: 'product',
            scope: {
              include: [{ relation: 'productPrices' }, { relation: 'stocks' }],
            },

          },
          ],
        }, filter);
      }

But I am unable to perform a filter on this url like

users/29/carts/prices?filter[where][cart_id]=29

The above query doesn't filter records where cart_id is 29. What is going wrong?

Thank you in advance

@agnes512 agnes512 self-assigned this Feb 13, 2020
@pratikjaiswal15
Copy link
Author

Any update sir @agnes512

@agnes512
Copy link
Contributor

@pratikjaiswal15 From your description, I guess you'd like to combine the where clause with the include clause. But notice that for the find() method, from the API docs, it takes 2 params:

find(
    filter?: Filter<T>,
    options?: Options,
  ): Promise<>{..}

That's why your filter filter[where][cart_id]=29 gets discarded, and

return this.usersRepository.carts(id).find({
          include: [{
            relation: 'product',
            scope: {
              include: [{ relation: 'productPrices' }, { relation: 'stocks' }],
            },

          },
          ],
        }, filter);

would only return all products with their related Stock and ProductPrice.

Basically, you need to combine these 2 filter. Here are two ways to do so::

  1. use filterBuilder ( a formal, safer way):
    add: import filterBuilder from '@loopback/repository';
    modify your endpoint:
get('/users/{id}/carts/prices', {
...
      })
      async Multiple_relation(
        @param.path.number('id') id: number,
        @param.query.object('filter') filter?: Filter<Cart>,
      ): Promise<Cart[]> {
         // define the where clause here. You might want to check the existence of filter.where
         const where = filter!.where as Where<Cart>; 
        // if your filter might contain other clauses, you need to define and add them to the filterBuilder respectively 

         const filterBuilder = new FilterBuilder();
         const newFilter = filterBuilder
          .include(
             {relation: 'product',  scope: { include: [{ relation: 'productPrices' }, { relation: 'stocks' }]}}
          )
         .where(where);  // the where clause you defined above
         .build();

    return this.usersRepository.carts(id).find(newFilter);
}
  1. Just combine these two filters if you make sure that you would only simply have the where clause in your query:
get('/users/{id}/carts/prices', {
...
      })
      async Multiple_relation(
        @param.path.number('id') id: number,
        @param.query.object('filter') filter?: Filter<Cart>,
      ): Promise<Cart[]> {
      // combine 2 filters
      const myFilter = {...filter, include: [{
        relation: 'product',
        scope: {
          include: [{ relation: 'productPrices' }, { relation: 'stocks' }],
        },
       }],
     };
  return this.usersRepository.carts(id).find(myFilter);
}

@pratikjaiswal15
Copy link
Author

pratikjaiswal15 commented Feb 15, 2020 via email

@achrinza
Copy link
Member

achrinza commented Feb 15, 2020

@agnes512 AFAIK filterBuilder (and similar functions) aren't documented. Should this go under Working with Data?

See #2527

@agnes512
Copy link
Contributor

@achrinza Do you mean the page that we are having for LB4?

@achrinza
Copy link
Member

achrinza commented Feb 17, 2020 via email

@agnes512
Copy link
Contributor

That's a good suggestion! filterBuilder would be helpful to simplifies the query syntax for use cases like this.

@agnes512
Copy link
Contributor

I am closing the issue. Feel free to reopen it if you have any questions, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants