Overview
One of the things that, in addition to being immensely convenient during the prototyping of an application, can also be favorable to us during the production environment. That is, it helps us from the ideation process and application creation to the production environment.
As you may have noticed by the title of the article, or I decided to create a simple article in which we use one of the most popular ORM's and we are going to seed our database.
Database seeding can be done in different contexts, from inserting random batches so that we can test our application faster (which helps in our development experience), but we can also define an array of objects that can be data. admin accounts or simply data that needs to be used in the production environment.
In today's example I will explain how we can insert random data into our database, as well as how we will establish a relationship between them. In the end we will have an API that will have only two endpoints, one to fetch all users and their articles, the other to fetch all articles and their authors.
I also add that in this article I will not explain how to create an API using Express, TypeORM and TypeScript. I will just explain how to implement the seeding of our database in an existing API. If you want access to the github repository with the final result of this article, you can click here.
Let's code
In the root of our project (where the package.json is located) we will install the following dependencies:
npm install typeorm-seeding faker --save
npm install @types/faker --save-dev
Now I will explain two things that I think are fundamental about the library we are going to use (typeorm-seeding).
The first thing I will talk about is Factories, basically for each entity we have in our application we will define a factory and this will be responsible for generating the data that will populate our application. Each of these data corresponds to the properties that we have defined in our entity.
So let's assume that these are your entities:
// @/src/db/entities/user.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
OneToMany,
BaseEntity,
} from "typeorm";
import { Post } from "./post";
@Entity()
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column()
name!: string;
@OneToMany(() => Post, (post) => post.user)
posts?: Post[];
}
// @/src/db/entities/post.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
BaseEntity,
} from "typeorm";
import { User } from "./user";
@Entity()
export class Post extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column()
title!: string;
@Column()
description!: string;
@Column({ type: "boolean", default: false })
isPublished!: boolean;
@ManyToOne(() => User, (user) => user.posts)
user!: User;
}
In the case of the user entity, we will need to generate only the username, which would correspond to this factory:
// @/src/db/seeding/factories/user.factory.ts
import * as Faker from "faker";
import { define } from "typeorm-seeding";
import { User } from "../../entities";
define(User, (faker: typeof Faker) => {
const user = new User();
const firstName = faker.name.firstName();
const lastName = faker.name.lastName();
user.name = `${firstName} ${lastName}`;
return user;
});
And in the case of the post, it would be like this:
// @/src/db/seeding/factories/post.factory.ts
import * as Faker from "faker";
import { define } from "typeorm-seeding";
import { Post } from "../../entities";
define(Post, (faker: typeof Faker) => {
const post = new Post();
post.title = faker.lorem.words(8);
post.description = faker.lorem.paragraph(6);
post.isPublished = faker.random.boolean();
return post;
});
Now with our factories defined, as soon as we define how many users or articles we want to create, the factory will always generate random values in each of the properties.
Now we can move to the Seeder, the seeder is a class that is used to execute the seeding of our database and here I want you to be careful with the name, because the name of the seed corresponds to the name of the class (and not of the file ).
The boilerplate of a Seeder is as follows:
// @/src/db/seeding/seeds/initialSeed.ts
import { Factory, Seeder } from "typeorm-seeding";
import { Connection } from "typeorm";
// ...
export default class InitialDatabaseSeed implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<void> {
// ...
}
}
What we need to do first is import our entities, which we are going to seed.
// @/src/db/seeding/seeds/initialSeed.ts
import { Factory, Seeder } from "typeorm-seeding";
import { Connection } from "typeorm";
import { User, Post } from "../../entities";
export default class InitialDatabaseSeed implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<void> {
// ...
}
}
Now let's seed the users table first and define that we want to insert 15 users in the table in total.
// @/src/db/seeding/seeds/initialSeed.ts
import { Factory, Seeder } from "typeorm-seeding";
import { Connection } from "typeorm";
import { User, Post } from "../../entities";
export default class InitialDatabaseSeed implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<void> {
const users = await factory(User)().createMany(15);
// ...
}
}
With the users created, we are now going to generate the articles, but this time, in addition to defining the number of articles we want to generate, we will also pass the user who must be the author of the article. In this case we have to assign it in a random way. Like this:
// @/src/db/seeding/seeds/initialSeed.ts
import { Factory, Seeder } from "typeorm-seeding";
import { Connection } from "typeorm";
import { User, Post } from "../../entities";
export default class InitialDatabaseSeed implements Seeder {
public async run(factory: Factory, connection: Connection): Promise<void> {
const users = await factory(User)().createMany(15);
await factory(Post)()
.map(async (post) => {
post.user = users[Math.floor(Math.random() * users.length)];
return post;
})
.createMany(100);
}
}
With our factories defined and our seeder created, the next step is to define the directories where our factories and our seeders are in our TypeORM configuration.
// @/ormconfig.ts
import { User, Post } from "./src/db/entities";
export default {
name: "default",
type: "sqlite",
database: "src/db/dev.db",
entities: [User, Post],
synchronize: true,
logging: false,
// These two lines have been added:
seeds: ["src/db/seeding/seeds/**/*{.ts,.js}"],
factories: ["src/db/seeding/factories/**/*{.ts,.js}"],
};
Finally, just go to our package.json
and create the script that will be responsible for seeding our database.
// @/package.json
{
// ...
"scripts": {
// ...
"db:seed": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed"
},
// ...
}
Don't forget to have your API process running and run the command npm run db:seed
to seed your database.
Conclusion
As always, I hope you found it interesting. If you noticed any errors in this article, please mention them in the comments. 🧑🏻💻
Hope you have a great day! 👋 🌱
Top comments (13)
thanks for sharing
Nice post but a long time has passed since this it was written. So I just wrote an up-to-date one on my blog, for thoes who are in need in these times:
How to seed a database with typeorm and faker in 2023
The link does not work
Thank you for notifying, I've just updated it now.
is not working 😩
correct link is devist.xyz/posts/how-to-seed-a-dat...
Thanks for sharing😉
seeds: ["src/db/seeding/seeds//*{.ts,.js}"],
factories: ["src/db/seeding/factories//*{.ts,.js}"],
Does not work with nestjs
TypeOrmModule.forRoot({
type: process.env.DB_TYPE as any,
host: process.env.DB_HOSTNAME,
port: Number(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: [Book, Page],
seeds: [InitialDatabaseSeed],
factories: ['src/db/seeding/factories/**/*{.ts,.js}'],
synchronize: true,
logging: process.env.NODE_ENV !== 'production',
}),
Help me
Hi, if you run
npm run db:seed
two time, is it going to generate 30 users and 200 posts even though you have only one seed?អរគុណ😻
Thanks for sharing.. Is there a way to use this inside an Nx Monorepo ?
Thanks for sharing this articel, really help me a lot.
✖ Could not load the config file!