🕌

マイグレーション時にデータも変更/移行する方法(laravel)

2021/07/02に公開

マイグレーションをした際に、データを変更したり、移行したりする場合があると思います。

例えば、 記事にタグ付けする際にタグは3つまで!って決まっていのに、仕様変更で無限にタグ付けできるようにしたい場合。想像してみてください。

これまでarticlesテーブルにタグ1, タグ2, タグ3といれていました。

articles
  - id
  - title
  - thumbnail_url
  - tag1
  - tag2
  - tag3

しかし、無限にできるということは 新しくtagsテーブルを作ってarticlesテーブルと紐付けしないといけない!
そうなると、過去のデータも全部tagsテーブルに移行しないといけない!

という風になります。

articles
  - id
  - title
  - thumbnail_url
  
tags
  - id
  - name
  - article_id

そんなときはtagsテーブルを作り、articlesテーブルからtagsにタグ情報を移行させる必要があります。

そのデータ以降もマイグレーションファイル内で記述するとめちゃくちゃ便利なのです!

1. tagsテーブルを作る

新たにtagsテーブルを新設するので、マイグレーションでtagsテーブルを作成します。

php artisan make:migration create_tags

マイグレーションファイルを作っていきます。

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTags extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
 
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
	    $table->integer("article_id")->unsigned();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropTable("tags");
    }
}

2. データを移行する

データを移行するためのマイグレーションファイルを作っていきます。

php artisan make:migration transfer_data_from_articles_to_tags

マイグレーションファイルを作っていきます。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class TransferDataFromArticlesToTags extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // データを移行する
        $articles = Articles::all();
        foreach ($articles as $article) {
	    if ($article->tag1) {
	        Tag::create(["article_id" => $article->id, "name" => $article->tag1]);
	    }
	    if ($article->tag2) {
	        Tag::create(["article_id" => $article->id, "name" => $article->tag2]);
	    }
	    if ($article->tag3) {
	        Tag::create(["article_id" => $article->id, "name" => $article->tag3]);
	    }
	}
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // ロールバック処理(本当はしっかり書いた方が良いかと)
    }
}

このようにマイグレーションの内部でデータ移行の処理を書いてしまいます。
マイグレーションは基本スキーマの変更がメインなので、スキーママイグレーションしか書いちゃダメだと感じてしまいますが、個人的にはデータの変更・移行のようなデータマイグレーションも書いちゃって良いと思います。

ロールバックもできて便利ですし、ヒューマンエーラは発生しないですし、ローカルでもステージングでも本番でも php artisan migrate でデータが移行できるなんて超便利
※十分の注意を払ってくださいね(笑)

articlesのtag1, tag2, tag3を削除する

articlesのtagカラムを削除するためのマイグレーションを作成します

php artisan make:migration remove_tags_column_from_articles --table="artilces"

マイグレーションファイルを仕上げていきます。

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTags extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
 
        Schema::table('articles', function (Blueprint $table) {
            $table->dropColumn("tag1");
	    $table->dropColumn("tag2");
	    $table->dropColumn("tag3");
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->string("tag1")->after("name");
	    $table->string("tag2")->after("tag1");
	    $table->string("tag3")->after("tag2");
        });
    }
}

終わりに

本記事で伝えたかったことは、ステップ2の部分でマイグレーションファイル内でデータを移行することについてです。

なかなかマイグレーションファイル内でデータ移行の処理を書くことがないかとは思いますが、
同じデータベース内で、データを変更したり移行したりすることがあればぜひ参考にしてみてください。

Discussion