Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Inner Join to work on TypeORM?

Tags:

typeorm

nestjs

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;
}
like image 387
MrRobot Avatar asked Dec 31 '20 22:12

MrRobot


People also ask

How to enhance the relationship between entities in typeorm?

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.

How to create Query Builder using repository in typeorm?

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.

How to create a typeorm project using typeorm?

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.

How to integrate typeorm with express application?

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.


2 Answers

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();
like image 162
Cem Avatar answered Sep 28 '22 06:09

Cem


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.

like image 36
Adeel Shekhani Avatar answered Sep 28 '22 05:09

Adeel Shekhani