> For the complete documentation index, see [llms.txt](https://saveyourtime.gitbook.io/saveyourtime/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://saveyourtime.gitbook.io/saveyourtime/backend/typeorm-how-to-seed-data-with-typeorm-seeding.md).

# 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/>
