Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SequelizeJS - How to Map Nested (eager loading) Models for Raw Queries?

Below is an example of a raw query.

  const query = `SELECT 
    links.name, links.type, links.code, links.originalUrl,
    domains.id as 'domain.id', domains.host as 'domain.host',

    count(
      CASE WHEN hits.datetime > "${past}" AND hits.datetime <= "${now}" = true then 1 END
    ) as hitCount 

    FROM links

    LEFT JOIN hits ON links.id = hits.linkId
    LEFT JOIN domains ON links.domainId = domains.id

    WHERE links.userId = ${req.user.id}

    GROUP BY links.id, hits.linkId

    ORDER BY hitCount DESC

    LIMIT 5`;

  const links = await sequelize.query(query.trim(), { 
    type: sequelize.QueryTypes.SELECT,
    model: Link,
    mapToModel: true
  });

I am mapping the query result into the model Link with mapToModel: true. It works well but when I try to get some data from a joined table and map that into an object in model it doesn't convert into array.

For example I am trying to get domains like domains.id as 'domain.id', domains.host as 'domain.host', This is how I saw sequlize does the query for eager loaded data.

But when I get the result object the I don't get a nested domain object property.

// desired link object
{
   id: 3,
   name: 'My test link',
   domain: {
      id: 23,
      host: 'example.com'
   }
}

instead what I get is

// current link object
{
   id: 3,
   name: 'My test link',
   'domain.id': 23,
   'domain.host': 'example.com'
}

So nested objects aren't mapping correctly.

UPDATE

I have found nest options in query() documentation but setting nest: true doesn't seems to have any effect.

Changed Query

  const links = await sequelize.query(query.trim(), { 
    type: sequelize.QueryTypes.SELECT,
    model: Link,
    mapToModel: true,
    nest: true, // doesn't have any effect
  });
like image 409
Sisir Avatar asked Apr 05 '19 06:04

Sisir


People also ask

What is Sequelize eager loading in SQL?

Sequelize eager loading is a way to fetch data from multiple tables that have relations between each other. When you use the eager loading technique, the generated SQL query will have one or more JOIN clauses. Let’s see an example of Sequelize eager loading in action.

What is the use of Sequelize query?

As there are often use cases in which it is just easier to execute raw / already prepared SQL queries, you can use the sequelize.query method. By default the function will return two arguments - a results array, and an object containing metadata (such as amount of affected rows, etc).

Can I map a query result to an object in model?

I am mapping the query result into the model Link with mapToModel: true. It works well but when I try to get some data from a joined table and map that into an object in model it doesn't convert into array.

What is the through parameter for in Sequelize?

When declaring many-to-many associations, Sequelize requires a through parameter, in which you pass in the name of the join table that represents that many-to-many relationship. (You can create your own model, as I did, but if you don't, Sequelize will auto-generate that join table for you-- but you still have to give it a name in through ).


2 Answers

For me nest worked only in conjunction with raw:

  const links = await sequelize.query(query.trim(), { 
    type: sequelize.QueryTypes.SELECT,
    model: Link,
    mapToModel: true,
    nest: true,
    raw: true // Without this `nest` hasn't effect, IDK why
  });
like image 122
Alex G.P. Avatar answered Sep 21 '22 07:09

Alex G.P.


I have run into the same problem. My solution was:

return sequelize.query(/* query */, {
    nest: true,
    type: sequelize.QueryTypes.SELECT
});

As you see, you should not set mapToModel prop, just nest and type.

like image 37
Alik Rakhmonov Avatar answered Sep 24 '22 07:09

Alik Rakhmonov