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

Filter by properties of related models (use SQL JOIN in queries) #683

Closed
bluestaralone opened this issue Oct 23, 2014 · 53 comments
Closed

Comments

@bluestaralone
Copy link

Ex: I have models Book and Category and i want to query Book with condition like below:
Books with title contain "Art" and belongs to Category "Programming", please tell me how to do it ?
I run this filter in Books model.
GET /Books

{"include":{"categories"}, "where": {"title":{"like":"^Art"}, "categories.name":"Programming"}}
@bajtos
Copy link
Member

bajtos commented Jun 2, 2016

See loopbackio/loopback-datasource-juggler#730 for a more detailed description of the requested feature.

@princecharmx
Copy link

+1

1 similar comment
@AlexYegupov
Copy link

+1

@codyolsen
Copy link
Contributor

codyolsen commented Aug 16, 2016

+1 Hope this gets accepted soon

@reneolivo
Copy link

+1 please! \0/

@ericalves
Copy link

+1 please!

@bajtos bajtos added the #tob label Sep 6, 2016
@bajtos bajtos changed the title How can i set condition where on include model ? Filter by properties of related models (use SQL JOIN in queries) Sep 6, 2016
@Amir-61 Amir-61 removed the #tob label Sep 6, 2016
@shuckepco
Copy link

This is definitely a "must have"!

@pierissimo
Copy link
Contributor

+1

@Amir-61 Amir-61 removed their assignment Oct 13, 2016
@bostondv
Copy link

+1

3 similar comments
@rusackas
Copy link

+1

@Simone-cogno
Copy link

+1

@jeff3yan
Copy link

+1

@bajtos
Copy link
Member

bajtos commented Nov 2, 2016

Please, don't spam everybody on this thread by posting +1 comments. Click on the "thumb up" icon at the top. It will also allow us to sort issues based on the number of upvotes.

@barocsi
Copy link

barocsi commented Jun 18, 2018

Boy, its broken at the core just as many "open source" framework, which itself is an illusion. These guys are obviously building apps for clients and not for community. We are good to be testers, pull requesters, fixers, but left fairly behind if it comes to an issue that is not in the interest of loopback main clients.

@Andresagustin
Copy link

+1

@cantoute
Copy link

cantoute commented Jun 30, 2018

Is this going to be implemented on lb4 ?
seems unreal at this level to be stuck with things as basic as that.

@kurtommy
Copy link

kurtommy commented Jul 1, 2018

@barocsi well a lot of time the trigger to build huge open source libs is: some company needs and build a framework and then is released publicly eg Angular React ....
I believe that the lack of doing SQL Join is a major / huge problems that also the ibm customers will face.

So as @cantoute is saying this situation is absolutely unreal.

I'd like to mention @bajtos as maintainer to ask him if there are some updates on this topic

@bajtos
Copy link
Member

bajtos commented Jul 2, 2018

I don't have any update to share. Our focus is on delivering LoopBack 4.0 GA, we don't have bandwidth to work on this feature until 4.0 is released.

@dionisisZyg
Copy link

@bajtos Sorry to bother you, but since the Loopback 4.0 is released is there anything planed for this feature?

Thanks!

@bkstorm
Copy link

bkstorm commented Nov 1, 2018

I can't believe that Loopback doesn't support this basic feature. Does Loopback 4.0 support it?
To resolve this problem, I have to use native sql.

@cantoute
Copy link

cantoute commented Nov 1, 2018 via email

@pookdeveloper
Copy link

This is not resolved yet? Thanks

@pookdeveloper
Copy link

pookdeveloper commented Dec 3, 2018

if this is not resolved:

#683

Why in the docu are this ?

https://loopback.io/doc/en/lb3/Include-filter.html

image

Thanks

@bajtos
Copy link
Member

bajtos commented Dec 3, 2018

@pookdeveloper IIUC, the condition specified in include.scope.where is applied only to related models being fetched. This issue is asking for a different feature: filter the source models based on properties of the related model.

What does not work:

Books with title contain "Art" and belongs to Category "Programming"

What may work using include.scope.where:

Books with title containing "Art", include data of all related categories with the name "Programming".

I hope my example is making the difference clear.

@afilp
Copy link

afilp commented Apr 14, 2019

Is Loopback 4 supporting this now?

@vncdias
Copy link

vncdias commented May 3, 2019

Is there any update on this?

@Rayjax
Copy link

Rayjax commented May 10, 2019

This is completely insane.

@pookdeveloper
Copy link

I can do that with typeorm https://typeorm.io/#/

@afilp
Copy link

afilp commented May 10, 2019

@pookdeveloper You mean that you use typeorm as a total replacement of loopback? Or combined?

@pookdeveloper
Copy link

@pookdeveloper You mean that you use typeorm as a total replacement of loopback? Or combined?

I use combined

@afilp
Copy link

afilp commented May 11, 2019

@pookdeveloper Thank you, is somewhere a tutorial on how we can setup this solution? It seems that this can solve many problems that loopback has not addressed yet.

@pookdeveloper
Copy link

I will try today to do a tutorial

@melochale
Copy link

@pookdeveloper could you please give us an example? thanks very much!

@pookdeveloper
Copy link

@melote @afilp i'm writting a tutorial, i will send you the link

@pookdeveloper
Copy link

@alexdee2007
Copy link

alexdee2007 commented Mar 21, 2020

It's not hard to just override the _buildWhere method at boot time.
For example (i use Oracle DB)

const set = require('lodash/set');

module.exports = function (app) {
  const connector = app.dataSources.db.connector;
  const _buildWhere = connector._buildWhere.bind(connector);

  connector._buildWhere = function (model, where) {

    for (var key in where) {
      if (key.includes('.')) {
        Object.assign(where, set({}, key, where[key]));
        delete where[key];
      }
    }

    let whereClause = _buildWhere(model, where);
    const relations = app.models[model].relations;

    for (const key in where) {
      if (relations && relations[key]) {
        const relation = relations[key];
        const inSelect = this.buildSelect(relation.modelTo.modelName, {
          fields: [relation.keyTo],
          where: {
            and: [
              app.models[model]._coerce(where[key], {}, app.models[relation.modelTo.modelName].definition)
            ]
          }
        }, {parameterize: false, order: false});
        whereClause = new ParameterizedSQL({
          sql: whereClause.sql + (whereClause.sql !== '' ? ' AND ' : '') + this.columnEscaped(relation.modelFrom.modelName, relation.keyFrom) + ' IN (' + inSelect.sql + ')',
          params: whereClause.params.concat(inSelect.params),
        });
      }
    }
    return whereClause;
  }
}

And then
GET /Books

{"include":{"categories"}, "where": {"title":{"like":"^Art"}, "categories.name":"Programming"}}

or just

{"where": {"categories.name":"Programming"}}

or even

{"where": {"models1.models2.models3.field":"someValue"}}

{"where":{"models1":{"and":[{"someField1":"someValue1"},{"someField2":"someValue2"}]}}}

@mituso89
Copy link

mituso89 commented Oct 1, 2020

It's not hard to just override the _buildWhere method at boot time.
For example (i use Oracle DB)

const set = require('lodash/set');

module.exports = function (app) {
  const connector = app.dataSources.db.connector;
  const _buildWhere = connector._buildWhere.bind(connector);

  connector._buildWhere = function (model, where) {

    for (var key in where) {
      if (key.includes('.')) {
        Object.assign(where, set({}, key, where[key]));
        delete where[key];
      }
    }

    let whereClause = _buildWhere(model, where);
    const relations = app.models[model].relations;

    for (const key in where) {
      if (relations && relations[key]) {
        const relation = relations[key];
        const inSelect = this.buildSelect(relation.modelTo.modelName, {
          fields: [relation.keyTo],
          where: {
            and: [
              app.models[model]._coerce(where[key], {}, app.models[relation.modelTo.modelName].definition)
            ]
          }
        }, {parameterize: false, order: false});
        whereClause = new ParameterizedSQL({
          sql: whereClause.sql + (whereClause.sql !== '' ? ' AND ' : '') + this.columnEscaped(relation.modelFrom.modelName, relation.keyFrom) + ' IN (' + inSelect.sql + ')',
          params: whereClause.params.concat(inSelect.params),
        });
      }
    }
    return whereClause;
  }
}

And then
GET /Books

{"include":{"categories"}, "where": {"title":{"like":"^Art"}, "categories.name":"Programming"}}

or just

{"where": {"categories.name":"Programming"}}

or even

{"where": {"models1.models2.models3.field":"someValue"}}

{"where":{"models1":{"and":[{"someField1":"someValue1"},{"someField2":"someValue2"}]}}}

How to use it in loopback4?

@enisinanaj
Copy link

It's not hard to just override the _buildWhere method at boot time.
For example (i use Oracle DB)

const set = require('lodash/set');

module.exports = function (app) {
  const connector = app.dataSources.db.connector;
  const _buildWhere = connector._buildWhere.bind(connector);

  connector._buildWhere = function (model, where) {

    for (var key in where) {
      if (key.includes('.')) {
        Object.assign(where, set({}, key, where[key]));
        delete where[key];
      }
    }

    let whereClause = _buildWhere(model, where);
    const relations = app.models[model].relations;

    for (const key in where) {
      if (relations && relations[key]) {
        const relation = relations[key];
        const inSelect = this.buildSelect(relation.modelTo.modelName, {
          fields: [relation.keyTo],
          where: {
            and: [
              app.models[model]._coerce(where[key], {}, app.models[relation.modelTo.modelName].definition)
            ]
          }
        }, {parameterize: false, order: false});
        whereClause = new ParameterizedSQL({
          sql: whereClause.sql + (whereClause.sql !== '' ? ' AND ' : '') + this.columnEscaped(relation.modelFrom.modelName, relation.keyFrom) + ' IN (' + inSelect.sql + ')',
          params: whereClause.params.concat(inSelect.params),
        });
      }
    }
    return whereClause;
  }
}

And then
GET /Books

{"include":{"categories"}, "where": {"title":{"like":"^Art"}, "categories.name":"Programming"}}

or just

{"where": {"categories.name":"Programming"}}

or even

{"where": {"models1.models2.models3.field":"someValue"}}

{"where":{"models1":{"and":[{"someField1":"someValue1"},{"someField2":"someValue2"}]}}}

How to use it in loopback4?

where does ParameterizedSQL come from?

@alexdee2007
Copy link

@enisinanaj

const ParameterizedSQL = require('loopback-connector/lib/parameterized-sql');

@cantoute
Copy link

cantoute commented Nov 16, 2021

Or perhaps the way to go is switch to typeORM ....

But at this time support for it in lb is at useless... nestjs ?

@pandayamitray
Copy link

8 years and counting. Still, this basic feature is not there. If I would have known earlier about this, I would have not chosen LB4

@cantoute
Copy link

I switched to nestjs + typeorm and no regrets

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

No branches or pull requests