Prismaを使ってWordPressのデータベースにTypeScriptでアクセスする

Prismaでは、既存のDB情報からスキーマを作ることができます。 The db pull command connects to your database and adds Prisma models to your […]

広告ここから
広告ここまで

目次

    Prismaでは、既存のDB情報からスキーマを作ることができます。

    The db pull command connects to your database and adds Prisma models to your Prisma schema that reflect the current database schema.

    https://www.prisma.io/docs/reference/api-reference/command-reference#db-pull

    手持ちの稼働しているDBがWordPressのみでしたので、試しにつないでみました。

    前準備

    事前準備として、以下の作業を行います。

    • MySQLでDBに接続するためのユーザーを用意する
      • 事故防止のため、ユーザーはREAD権限のみにする
    • WordPressのDBが入っているサーバー(Amazon EC2)に、ローカルPCからMySQLで接続できるようにする

    Amazon EC2インスタンスに、MySQLで接続できるようにする

    AMIMOTO AMIなどでWordPressを立ち上げた場合、デフォルトではインスタンスにはMySQLで接続できません。

    セキュリティグループに、以下の情報を追加して、アクセスできるようにします。

                    {
                        "FromPort": 3306,
                        "IpProtocol": "tcp",
                        "IpRanges": [
                            {
                                "CidrIp": "xxx.xx.xx.xxx/32"
                            }
                        ],
                        "Ipv6Ranges": [],
                        "PrefixListIds": [],
                        "ToPort": 3306,
                        "UserIdGroupPairs": []
                    },

    MySQLで読み込み専用のユーザーを作成する

    続いてDBを読むためのユーザーを作成します。

    必要のないDBへアクセスさせたくないので、前もってデータベースの情報を確認します。

    mysql> show databases;
    +---------------------+
    | Database            |
    +---------------------+
    | information_schema  |
    | wp_db |
    | mysql               |
    | performance_schema  |
    | sys                 |
    +---------------------+
    5 rows in set (0.00 sec)

    WordPressの場合、wp-config.php(AMIMOTOではlocal-config.php)でもDB名は確認できます。

    アクセスさせたいデータベースの名前を確認したら、ユーザーを作成しましょう。

    mysql> CREATE USER 'nodejs'@'123.45.67.890' IDENTIFIED BY 'YOUR_PASSWORD';
    mysql> GRANT SELECT ON wp_db.* TO 'nodejs'@'123.45.67.890' IDENTIFIED BY 'YOUR_PASSWORD' WITH GRANT OPTION;

    パラメータはそれぞれ以下の通りです。

    • nodejs: DBにアクセスするためのユーザー名
    • 123.45.67.890: ユーザーのIPアドレス。今回は自分のIPを調べて設定
    • YOUR_PASSWORD: ユーザーのパスワード
    • wp_db: アクセスしたいデータベースの名前

    PrismaでDBに接続するプロジェクトをセットアップする

    ユーザーが作成できたので、Prismaで接続準備を始めます。

    % mkdir wordpress
    % cd wordpress 
    % npm init -y
    % npm install typescript ts-node @types/node --save-dev
    % touch tsconfig.json
    % npm install prisma --save-dev

    プロジェクトの作成後、セットアップコマンドを実行しましょう。

    % npx prisma init --datasource-provider mysql
    
    ✔ Your Prisma schema was created at prisma/schema.prisma
      You can now open it in your favorite editor.
    
    Next steps:
    1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
    2. Run prisma db pull to turn your database schema into a Prisma schema.
    3. Run prisma generate to generate the Prisma Client. You can then start querying your database.
    
    More information in our documentation:
    https://pris.ly/d/getting-started

    DATABASE_URLを環境変数で設定する必要があります。

    .envファイルが生成されているので、自分のDB情報に書き換えましょう。

    - DATABASE_URL="mysql://johndoe:randompassword@localhost:3306/mydb"
    + DATABASE_URL="mysql://nodejs:[email protected]:3306/wp_db"

    PrismaでWordPressのDB設定をpullする

    接続の設定ができていれば、あとはpullするだけです。

    % yarn prisma db pull
    yarn run v1.22.15
    $ /Users/sandbox/sql/wordpress/node_modules/.bin/prisma db pull
    Prisma schema loaded from prisma/schema.prisma
    Environment variables loaded from .env
    Datasource "db": MySQL database " wp_db" at "123.45.67.890:3306"
    
    ✔ Introspected 29 models and wrote them into prisma/schema.prisma in 4.54s
          
    Run yarn prisma generate to generate Prisma Client.
    
    ✨  Done in 6.38s.

    prisma/schema.prismaの中身が、DATABASE_URLに指定したDBの設定に合わせて変更されています。

    model wp_postmeta {
      meta_id    BigInt  @id @default(autoincrement()) @db.UnsignedBigInt
      post_id    BigInt  @default(0) @db.UnsignedBigInt
      meta_key   String? @db.VarChar(255)
      meta_value String? @db.LongText
    
      @@index([meta_key(length: 191)], map: "meta_key")
      @@index([post_id], map: "post_id")
    }
    ...

    generateコマンドを実行すると、クライアントコードに設定が反映されます。

    % prisma generate
    Environment variables loaded from .env
    Prisma schema loaded from prisma/schema.prisma
    
    added 2 packages, and audited 24 packages in 16s
    
    found 0 vulnerabilities
    
    ✔ Installed the @prisma/client and prisma packages in your project
    
    ✔ Generated Prisma Client (4.2.1 | library) to ./node_modules/@prisma/client in 365ms
    You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
    
    import { PrismaClient } from '@prisma/client'
    const prisma = new PrismaClient()
    
    ✨  Done in 19.67s.

    PrismaでWordPressの情報を取得する

    クライアントの設定が完了したので、実際にデータをよんでみましょう。

    import { PrismaClient } from '@prisma/client'
    const prisma = new PrismaClient()
    
    const main = async () => {
        const post = await prisma.wp_posts.findFirst({
            where: {
                ID: 2458
            }
        })
        return post
    }
    
    main().then(console.log).catch(console.log)

    このコードは、IDで特定の投稿を取得するクエリです。

    yarn ts-node ./PATH/TO/FILE.tsなどで実行すると、DBから結果が取得できます。

    wp_postmetaの情報から記事を検索する

    WordPressでクエリが複雑になりやすいケースの1つが、「特定のカスタムフィールド情報を持つ記事を取得する」です。

    せっかくなので、これをPrismaで実装してみましょう。

    import { PrismaClient } from '@prisma/client'
    const prisma = new PrismaClient()
    
    const main = async () => {
        const postsMeta = await prisma.wp_postmeta.findMany({
            select: {
                post_id: true,
                meta_key: true,
                meta_value: true,
            },
            where: {
                OR: [{
                    meta_key: "meta_keywords",
                    meta_value: {
                        not: ""
                    }
                },{
                    meta_key: {
                        contains: 'vkExUnit_cta'
                    },
                    meta_value: {
                        contains: 'Amazon'
                    },
                }],
            },
            take: 50,
        })
        const posts = await prisma.wp_posts.findMany({
            select: {
                ID: true,
                post_title: true,
            },
            where: {
                ID: {
                    in: postsMeta.map(meta => meta.post_id)
                }
            }
        })
        return posts.map(post => {
            const metaItems = postsMeta.filter(meta => meta.post_id === post.ID)
            if (!metaItems) return post
            return {
                ...post,
                ID: post.ID.toString(),
                post_meta: metaItems.map(item => {
                    return {
                        [item.meta_key]: item.meta_value
                    }
                }),
            }
        })
    }
    
    main().then(data => {
        console.log(JSON.stringify(data,null,2))
    }).catch(console.log)

    prisma.wp_postmetaに対してfindManyで検索をかけます。

    その後、取得できたデータのpost_idを使ってprisma.wp_postsにクエリを投げて、記事を取得しています。

    最後に、postmetaの情報をpostに追加して表示させましょう。

    このように情報が取得できます。

    [
      {
        "ID": "123",
        "post_title": "WordPressサイトの「ドメイン」の話",
        "post_meta": [
          {
            "meta_keywords": "ドメイン"
          }
        ]
      },
      {
        "ID": "456",
        "post_title": "サーバーレスシングルページアプリケーション",
        "post_meta": [
          {
            "vkExUnit_cta_button_text": "Amazonで買う"
          },
    ...

    使い道

    「Prisma使ってみたい」と「手持ちのDBがWordPressだった」の2つから始まったので、実用的かといわれるとちょっと悩ましいです。

    Amazon RDSなどでデータを管理している場合は、VPC Lambdaを使ってWordPressのDB情報を取得するのに使えるかもしれません。あとは複雑なクエリをもつAPIを、WordPressの知識なしに実現させたい場合や、すでにPrismaを使っているアプリでWordPressのDB情報も参照したい場合・・・などでしょうか。

    WooCommerceを入れている場合は、顧客や注文情報のクエリにも使えるかもしれません。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark