typeorm/docs/relational-query-builder.md
2017-10-03 15:35:09 +05:00

4.0 KiB

Working with Relations

RelationQueryBuilder is special type of QueryBuilder which allows you to work with your relations. Using it you can bind entities to each other in the database without need to load any entity. Or you can load related entities easily. Examples:

For example we have a Post entity and it has many-to-many relation to Category entity called categories. Let's add a new category to this many-to-many relation:

import {getConnection} from "typeorm";

await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(post)
    .add(category);

This code is equivalent of doing this:

import {getManager} from "typeorm";

const postRepository = getRepository(Post);
const post = await postRepository.findOneById(1, { relations: ["categories"] });
post.categories.push(category);
await postRepository.save(post);

But more efficient because it does minimal number of operations and binds entities in the database, unlike calling bulky save method call.

Also, benefit of such approach is that you don't need to load everything in entity relation before pushing into it. For example if you would had ten thousands categories inside a single post adding a new post into this list may become problematic for you, because standard way of doing is to load post with all ten thousands categories, push a new category and save it. Result is very heavy performance and basically inapplicable in production results. However, using RelationQueryBuilder completely solves this problem.

Also, there is no real need to use entities when you "bind" things, you can use entity ids instead. For example, lets add category with id = 3 into post with id = 1:

import {getConnection} from "typeorm";

await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(1)
    .add(3);

If you are using composite primary keys you have to pass them as id map, for example:

import {getConnection} from "typeorm";

await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of({ firstPostId: 1, secondPostId: 3 })
    .add({ firstCategoryId: 2, secondCategoryId: 4 });

Same way you add new entities, you can remove them:

import {getConnection} from "typeorm";

// this code removes a category from a given post
await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(post) // you can use just post id as well
    .remove(category); // you can use just category id as well

Adding and removing related entities works in many-to-many and one-to-many relations. For one-to-one and many-to-one relations use set method instead:

import {getConnection} from "typeorm";

// this code sets category of a given post
await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(post) // you can use just post id as well
    .set(category); // you can use just category id as well

If you want to unset a relation (set it to null), simply pass null to a set method:

import {getConnection} from "typeorm";

// this code unsets category of a given post
await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(post) // you can use just post id as well
    .set(null);

Besides updating relations relational query builder also allows you to load relational entities. For example, lets say we have inside a Post entity many-to-many categories relation and many-to-one user relation. To load those relations you can use following code:

import {getConnection} from "typeorm";

const post = await getConnection().manager.findOneById(Post, 1);

post.categories = await getConnection()
    .createQueryBuilder()
    .relation(Post, "categories")
    .of(post) // you can use just post id as well
    .loadMany();

post.author = await getConnection()
    .createQueryBuilder()
    .relation(User, "user")
    .of(post) // you can use just post id as well
    .loadOne();