Join three table using library knex.js - node.js

I am using knex.js
suppose we have three table :-
table1-- id,name,address
table2--id,city,sate,table1_id as fk
table3--id,housenumber,table1_id as fk
I want to join these three table using knex.js libraray of node and express
so that i want to get output json like this.
{
"id":1,
"name":"abc",
"address:"xyz",
"table2":{"id":1,"city":"ttt","state":"www" }//i want check if table1.id == table2.table1_id then put table details
"table3":[]//if no relation found between table1.id === table3.table1.id then kept it as an array
}

tl;dr knex is too low level tool for the thing you are trying to do, you should use an ORM for that kind of task
However you can do that with lots of manual work.
First you have to make the query with proper joins and creating aliases with table prefixes for each column of table to be able to get result data in a format where all data is in a flat array like:
knex('table1' as t1)
.join('table2 as t2', 't2.t1_id', 't1.id')
.select(
't1.id as t1_id',
't1.other_column as t1_other_column',
't2.id as t2_id', <more columns you want to extract>)
Results something like
[ { t1_id: 1, t1_other_column: 'foo', t2_id: 4}, ... more rows with flat data... }]
Then you need to write javascript code for restructuring flat data to nested objects.
But you should not do that kind of work manually. All knex based ORMs has already implemented general solutions for writing that kind of queries in easy manner.

Related

Select one column from Type-ORM query - Node

I have a type ORM query that returns five columns. I just want the company column returned but I need to select all five columns to generate the correct response.
Is there a way to wrap my query in another select statement or transform the results to just get the company column I want?
See my code below:
This is what the query returns currently:
https://i.stack.imgur.com/MghEJ.png
I want it to return:
https://i.stack.imgur.com/qkXJK.png
const qb = createQueryBuilder(Entity, 'stats_table');
qb.select('stats_table.company', 'company');
qb.addSelect('stats_table.title', 'title');
qb.addSelect('city_code');
qb.addSelect('country_code');
qb.addSelect('SUM(count)', 'sum');
qb.where('city_code IS NOT NULL OR country_code IS NOT NULL');
qb.addGroupBy('company');
qb.addGroupBy('stats_table.title');
qb.addGroupBy('country_code');
qb.addGroupBy('city_code');
qb.addOrderBy('sum', 'DESC');
qb.addOrderBy('company');
qb.addOrderBy('title');
qb.limit(3);
qb.cache(true);
return qb.getRawMany();
};```
[1]: https://i.stack.imgur.com/MghEJ.png
[2]: https://i.stack.imgur.com/qkXJK.png
TypeORM didn't meet my criteria, so I'm not experienced with it, but as long as it doesn't cause problems with TypeORM, I see an easy SQL solution and an almost as easy TypeScript solution.
The SQL solution is to simply not select the undesired columns. SQL will allow you to use fields you did not select in WHERE, GROUP BY, and/or ORDER BY clauses, though obviously you'll need to use 'SUM(count)' instead of 'sum' for the order. I have encountered some ORMs that are not happy with this though.
The TS solution is to map the return from qb.getRawMany() so that you only have the field you're interested in. Assuming getRawMany() is returning an array of objects, that would look something like this:
getRawMany().map(companyRecord => {return {company: companyRecord.company}});
That may not be exactly correct, I've taken the day off precisely because I'm sick and my brain is fuzzy enough I was making too many stupid mistakes, but the concept should work even if the code itself doesn't.
EDIT: Also note that map returns a new array, it does not modify the existing array, so you would use this in place of the getRawMany() when assigning, not after the assignment.

How to add a where clause to Sequelize functions?

I'm trying to use aggregate functions to extract multiple different sums from a table using multiple different where clauses.
I'm trying to do something like this:
model.findAll({
attributes:[
[sequelize.fn('sum', sequelize.col('columnA')), 'sumA1'], // need to add where:{condition1}
[sequelize.fn('sum', sequelize.col('columnB')), 'sumB1'], // need to add where:{condition1}
[sequelize.fn('sum', sequelize.col('columnA')), 'sumA2'], // need to add where:{condition2}
[sequelize.fn('sum', sequelize.col('columnB')), 'sumB2'], // need to add where:{condition2}
...
]
)}
So far I've managed to make this work using Promise.all and making different calls to the database for each "where clause condition" or getting all data from the table and using node to calculate the sums. Is there a better way of doing this using sequelize?
If you prefer the literal way then it would be simple with subquery where
model.findAll({
limit: 1,
attributes:[
[sequelize.literal(`(select sum(columnA) from table where date = '2021-01-05')`), 'testSum'],
...and so on
]
})
you see from basic SQL concept the thing you need to perform is subquery or the over() clause using the window in either cases you need have a raw query first and then try to convert it over to sequelize syntax.

Querying a composite key with multiple IN values with jOOQ

I have the following query:
SELECT *
FROM table
WHERE (id, other_id, status)
IN (
(1, 'XYZ', 'OK'),
(2, 'ZXY', 'OK') -- , ...
);
Is it possible to construct this query in a type-safe manner using jOOQ, preferably without generating composite keys? Is it possible to do this using jOOQ 3.11?
My apologies, it seems my Google-fu was not up to par. The opposite of this question can be found here: Use JOOQ to do a delete specifying multiple columns in a "not in" clause
For completeness' sake, so that other Google searches might be more immediately helpful, the solution is:
// can be populated using DSL.row(...); for each entry
Collection<? extends Row3<Long, String, String>> values = ...
dslContext.selectFrom(TABLE)
.where(DSL.row(ID, OTHER_ID, STATUS).in(values))
.fetch();
Relevant jOOQ documentation: https://www.jooq.org/doc/3.14/manual/sql-building/conditional-expressions/in-predicate-degree-n/
Your own answer already shows how to do this with a 1:1 translation from SQL to jOOQ using the IN predicate for degrees > 1.
Starting from jOOQ 3.14, there is also the option of using the new <embeddablePrimaryKeys/> flag in the code generator, which will produce embeddable types for all primary keys (and foreign keys referencing them). This will help never forget a key column on these queries, which is especially useful for joins.
Your query would look like this:
ctx.selectFrom(TABLE)
.where(TABLE.PK_NAME.in(
new PkNameRecord(1, "XYZ", "OK"),
new PkNameRecord(2, "ZXY", "OK")))
.fetch();
The query generated behind the scenes is the same as yours, using the 3 constraint columns for the predicate. If you add or remove a constraint from the key, the query will no longer compile. A join would look like this:
ctx.select()
.from(TABLE)
.join(OTHER_TABLE)
.on(TABLE.PK_NAME.eq(OTHER_TABLE.FK_NAME))
.fetch();
Or an implicit join would look like this:
ctx.select(OTHER_TABLE.table().fields(), OTHER_TABLE.fields())
.from(OTHER_TABLE)
.fetch();

How do I specify a primary key on table creation with haskellDB?

Currently I am using something like this:
dbCreateTable db "MyTable" [ ("Col1", (StringT, False)), ("Col2", (StringT, False)) ]
which works fine, but i'd like to make "Col1" the primary key. Do i need to go back to raw SQL?
edit:
This still seems to hold:
"The part of creating a database from Haskell itself is not very
useful, for example you cannot express foreign- and primary keys,
indexes and constraints. Even the most simple database will need
one of these."
From http://www.mijnadres.net/published/HaskellDB.pdf
As the edit notes, HaskellDB is not very good at creating tables at the moment. It's best to build a database first, and then extract the info.

Kohana 3.2 relationship - Joins

i have the current design in mysql :
Table filesubject
Is there a way in Kohana to set relationship in a way that if i make something like
ORM::factory('filesubject')->where('file_id','=',$file->id)->find_all()->as_array());
That i get all the joins from the other tables ?
I'm not sure about your question. To automatically join models, first setup your relationships ($_belongs_to etc) and then look at:
In your model:
ORM property: $_load_with. eg: protected $_load_with= array(model1, model2, etc)
Or at run time:
ORM method: with(). eg: ORM::factory('filesubject')->with('model')->with('model2')->find_all()
I don't think the as_array() function pulls in the joined data though. Once it's actually performing the join you'd need to overwrite as_array (or write your own function) to output the nested key/pair values from the joined properties.

Resources