# TypeORM - How to seed data with typeorm-seeding 🔥

![](/files/-MBAHFIsfm5sTOMgl3o6)

當你在進行專案開發（Development）時，通常資料庫裡面都需要一些進行測試用的假資料（Fake data）；或者，專案上線（Production）時，會需要有一些 `metadata` 在裡面。例如：角色（Roles）、權限（Permissions）...等等。

此時，你有兩種方式餵資料給資料庫。第一種，手動新增（Manually）；第二種，寫程式自動化（Automatically）新增，也就是我想介紹給大家的方式。

然而，寫程式自動化新增也有很多途徑，如果有上網做過功課的，看見最多的教學文件應該是使用 [`migration`](https://typeorm.io/#/migrations)。由於，跟 `migration` 相關的教學文章（如：[How to seed TypeORM](https://medium.com/@bansalsushil_34403/how-to-seed-typeorm-d9637a5948cc)）已經有太多了，我就不多加介紹。在這邊我想介紹另一種方式，使用 [`typeorm-seeding`](https://github.com/w3tecch/typeorm-seeding) 和 [`faker`](https://github.com/marak/Faker.js/) 這兩個套件，幫助我們餵資料給資料庫。

{% hint style="info" %}
Faker 是一個幫助我們產生假資料的套件，有許多方法可以使用。\
例如：`faker.name.lastName()`, `faker.internet.email()`, `faker.phone.phoneNumber()`
{% endhint %}

## Steps

1. Install `typeorm-seeding`, `@types/faker` (Optional, if you're using TypeScript)
2. Setup `seeds` and `factories`
3. Run seeder script with `ormconfig`

{% hint style="info" %}
這邊假設，你已經有 Entity 了。\
例如：`user.entity.ts`, `pet.entity.ts`, `role.entity.ts`
{% endhint %}

## Installation

```bash
npm i typeorm-seeding
# or
yarn add typeorm-seeding
```

Optional, if you're using TypeScript

```bash
npm install -D @types/faker
```

{% hint style="info" %}
We don't need to install`faker` manually, because it's a dependency as `typeorm-seeding`.
{% endhint %}

## What do we need?

1. Seeds
2. Factories

> 我們的資料夾結構（Folder Structure）如下：

* src
  * database
    * seeds
      * create-user.seed.ts
    * factories
      * user.factory.ts
  * user
    * user.entity.ts
* ormconfig.js

{% hint style="danger" %}
It is important that naming these files suffixed with `.seed.ts` and `.factory.ts`&#x20;

例如：`src/database/factories/user.factory.ts`&#x20;
{% endhint %}

## Build our first Factory

> src/database/factories/user.factory.ts

我們使用 typeorm-seeding 提供的方法 `define` 定義 `Factory`。\
Factory 的主要目的是：利用資料（fake data）來產生實體（Entity）。

第一個參數為：Entity\
第二個參數為：FactoryFunction，接收 `faker` 和 `context` 這兩個參數。

> faker：主要用來產生假資料。\
> context：則是呼叫此 factory 時，用來接收傳遞下來的參數。在這個範例中，我並沒有用到。

```typescript
export enum Gender {
  MALE = 'MALE',
  FEMALE = 'FEMALE',
  DIVERSE = 'DIVERSE',
}

```

```typescript
import Faker from 'faker';
import { define } from 'typeorm-seeding';
import { User } from '../../users/user.entity';
import { Gender } from '../../users/gender.enum';

define(User, (faker: typeof Faker) => {
  const firstName = faker.name.firstName();
  const lastName = faker.name.lastName();
  const email = faker.internet.exampleEmail(firstName, lastName);
  const phone = faker.phone.phoneNumber();
  const address = faker.address.streetAddress();
  const dateOfBirth = faker.date.past();
  const gender = faker.random.objectElement<Gender>(Gender);

  const user = new User();
  user.firstName = firstName;
  user.lastName = lastName;
  user.gender = gender;
  user.email = email;
  user.phone = phone;
  user.address = address;
  user.dateOfBirth = dateOfBirth;
  return user;
});

```

## Create our CreateUsers Seeder

> src/database/seeds/create-user.seed.ts

有了 `Factory` 之後，我們可以來建立我們的 `Seeder` 了。\
Seeder 是我們利用 factory 產生假資料，並寫入資料庫的地方。<br>

首先，我們需要將我們的 CreateUser Seeder 用 `implements` 實踐來自 typeorm-seeding 的 `Seeder`。\
接著我們就可以使用 Seeder 預設提供的一個 `run` 方法（method），和 `define` 一樣，提供兩個參數。

第一個參數為：Factory，透過呼叫 factory()() 來產生實體（Entity）並取得 EntityFactory。（HOF 用法）\
第二個參數為：Connection，來自 typeorm 的 Connection。在這個範例中，我並沒有用到。

> factory：第一個 () 接收 Entity，第二個 () 接收自定義的內容，自定義的內容會被傳送到 Factory 的第二個參數 context 中。例如：`factory(User)('Hi, my name is Aaron')`

```typescript
import { Factory, Seeder } from 'typeorm-seeding';
import { User } from '../../users/user.entity';

export default class CreateUsers implements Seeder {
  public async run(factory: Factory): Promise<void> {
    await factory(User)().createMany(10);
  }
}

```

{% hint style="info" %}
當你有多個 seed 檔案時，預設執行順序將按照字母順序執行。
{% endhint %}

## Entity Factory

Entity Factory 透過執行 `factory(User)()` 後取得，他是一個已經跟 `Entity` 結合的 `Factory`，可以用來將實體寫入資料庫。

提供了幾個方法（method），例如：`map`, `create`, `createMany`, `make`, `makeMany`。

```typescript
const userEntityFactory = factory(User)();
await userEntityFactory.create();
await userEntityFactory.createMany(10);
await userEntityFactory.make();
await userEntityFactory.makeMany(10);
```

{% hint style="info" %}
`create` 與 `make` 最大的差別在於，`create` 會將資料寫入資料庫，而 `make` 不會。
{% endhint %}

> 詳細用法，請查閱：[EntityFactory](https://github.com/w3tecch/typeorm-seeding#entityfactory)

## Seed data to our database

當我們的 `Factory` 與 `Seeder` 都設定好了之後，我們就可以餵資料到資料庫了！

首先，我們需要告訴 `typeorm-seeder`，我們的 seeds 跟 factories 在哪裡，在你的 `ormconfig.js` 加入...

> ormconfig.js

```javascript
module.exports = {
  ...
  seeds: ['src/seeds/**/*{.ts,.js}'],
  factories: ['src/factories/**/*{.ts,.js}'],
}

```

接著，就可以執行 seed 的指令了。為了方便我們將指令加入 scripts 中。

> package.json

```javascript
"scripts": {
  "seed:config": "ts-node ./node_modules/typeorm-seeding/dist/cli.js config"
  "seed:run": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed"
  ...
}
```

## Run the script to seed data

最後就可以用程式自動化餵資料到資料庫啦～🔥

```bash
npm run seed:run
# or
yarn seed:run
```

## Caution

{% hint style="warning" %}
預設你的 `ormconfig.js` 在專案的根目錄中，而且名稱為 `ormconfig.js`

如果路徑與檔名不一樣，則可以透過 `--configName (or -n)` 與 `--root (or -r)`，指定檔案位置與檔案名稱。
{% endhint %}

假設你的 `ormconfig.js` 放在 `src/config/ormconfig.js`，則需設定為...&#x20;

{% hint style="success" %}
`-n ./src/config/ormconfig.js`

```javascript
"scripts": {
  "seed:config": "ts-node ./node_modules/typeorm-seeding/dist/cli.js config -n ./src/config/ormconfig.js",
  "seed:run": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -n ./src/config/ormconfig.js"
  ...
}
```

{% endhint %}

經測試過後發現`--root` 跟想像中的設定有落差。若使用 `-r` 則會噴以下錯誤。

{% hint style="danger" %}
`-r ./src/config (Don't do this!)`

```javascript
"scripts": {
  "seed:config": "ts-node ./node_modules/typeorm-seeding/dist/cli.js config -r ./src/config",
  "seed:run": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -r ./src/config"
  ...
}
```

{% endhint %}

![](/files/-MBCAmAZBKEJ9GQx9HaR)

## Reference

* <https://github.com/w3tecch/typeorm-seeding>
* <https://github.com/marak/Faker.js/>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://saveyourtime.gitbook.io/saveyourtime/backend/typeorm-how-to-seed-data-with-typeorm-seeding.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
