I'm trying to build a simple query on TypeORM but I'm not getting the entire data using INNER JOIN. What am I doing wrong?
The SQL query runs perfectly but the typeorm one just returns me the data for the 'watcher' table.
SQL Query
SELECT *
FROM watcher w
INNER JOIN user
ON w.userId = user.id;
TypeORM
async getSystemWideWatchers(): Promise<any[]> {
const query = this.createQueryBuilder('watcher');
const result = await query.innerJoin('user', 'u', 'watcher.userId = u.id').getMany();
console.log(result)
return result;
}
For example, an article may be tagged under multiple topic like programming language, finance, etc., and at the same time a particular tag may have multiple articles as well. TypeORM also provides options to enhance the relationship of the entities. They are as follows − eager − Source entity object loads the target entity objects as well.
We can use repository to create query builder. It is described below, import {getRepository} from "typeorm"; const user = await getRepository (User) .createQueryBuilder ("user") .where ("user.id = :id", { id: 1 }) .getOne (); Aliases are same as SQL alias.
Open a command prompt and go to your workspace. Run below command to create a TypeORM project. typeorm init --name typeorm-javascript-student-app --database mysql Open package.json file to remove the typescipt references. Removed the devDependencies section and typescript related package in dependences section.
As we seen in this chapter, TypeORM can be easily integrated into express application. Migrations are like version control for your database. It is used to modify and share application’s database schema. This section explains about how migrations works in TypeORM. To create a new migration, first we need to setup connection in ormconfig.json.
TypeORM has a method called innerJoinAndSelect
. You use plain innerJoin
. That is why user table is not selected from.
Once you change that part to innerJoinAndSelect
, watch table will be selected from. However, getMany
and getOne
returns objects with your Entity type. Therefore, if your Entity types do not have the relationships between User and Watcher tables, selected columns will not be included in the returned object.
Before I show you how to add these relations, I want to mention that you have the option to use getRawMany
function to get all selected columns, but I don't recommend using it, since relationships are much tidier (no raw column names, you get arrays of Entities corresponding to relationships) and in your case, there is no reason not to use relationships.
Now, the way I understand your database design, you have Users, and Users have Watchers. A Watcher watches only one User, and there may be multiple Watchers that watch the same user.
In this case, the relationship of User to Watcher is called "One to Many".
The relationship of Watcher to User is called "Many to One".
You need to specify this information in your Entity. Here is an example. Notice the OneToMany
decorator.
@Entity()
export class User {
@PrimaryColumn()
id: number;
@Column()
userName: string;
@OneToMany(type => Watcher, watcher => watcher.user)
watchers: Watcher[];
}
Here is the corresponding Watcher Entity:
@Entity()
export class Watcher {
@PrimaryColumn()
id: number;
@Column()
watcherName: string;
// we can omit this (and the join condition), if userId is a foreign key
@Column()
userId: number;
@ManyToOne(type => User, user => user.watchers)
user: User;
}
Once you have these relationships, you can select a User, along with all their Watchers, or vice versa (select a Watcher with the User they watch).
Here is how you do both:
// Select a user and all their watchers
const query = createQueryBuilder('user', 'u')
.innerJoinAndSelect('u.watchers', 'w'); // 'w.userId = u.id' may be omitted
const result = await query.getMany();
(If you want to include users with no watchers, you use leftJoin instead of innerJoin, as you probably know.)
This is probably what you were initially trying to do:
// Select a watcher and the user they watch
const query = createQueryBuilder('watcher', 'w')
.innerJoinAndSelect('w.user', 'u'); // 'w.userId = u.id' may be omitted
const result = await query.getMany();
Just in case someone runs into another scenario. Adding to what Cem answered. If there's no relationship defined in the database then you can do the following :
const query = createQueryBuilder('user', 'u')
.innerJoinAndMapMany(
'u.ObjectNameToMapDataOn',
EntityName,// or 'tableName'
'IAmAlias',
'u.columnName= IAmAlias.columnName'
)
similarly , innerJoinAndMapOne can be used. Depends on your case if you expect to have multiple records with joining table or single record.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With