AI Automate Lab
Discord Bot 中級

DiscordスプレッドシートDB×GAS実装ガイド

著者: れん (更新: ) 約15分で読了
#Discord #スプレッドシート #GAS #Bot #データベース

この記事はGASでできること完全ガイドの実装編です。 「GASとは何か」から知りたい方は、先にそちらをご覧ください。

この記事では、Google Apps Script(GAS)でスプレッドシートをデータベースとして使うDiscord Botを約60分で構築する手順を解説します。 排他制御付きのデータ登録・照会機能まで、コードをコピペするだけで動くように全コードを掲載しています。

この記事の前提

項目内容
必要なアカウントGoogle、Discord(サーバー管理権限)
必要な知識GAS入門ガイドを読了済み
所要時間約60分
費用0円(GAS・Discord無料、2026年2月時点)
完成物スプレッドシートにデータを登録・照会するDiscord Bot

この記事で作るもの

DiscordスプレッドシートDBとは、Googleスプレッドシートをデータベース代わりに使い、Discord Botからデータの登録・照会を行う仕組みです。専用のデータベースサーバーを用意せずに、無料でDiscordデータ管理機能を構築できます。

ユーザーがDiscordで「/add 商品A 50」と入力
  → GASがスプレッドシートに在庫データを登録(排他制御付き)
ユーザーがDiscordで「/list」と入力
  → GASがスプレッドシートから在庫一覧を取得して表示

スプレッドシートDBと本格DBの比較

項目スプレッドシートDB本格DB(Firestore等)
費用無料無料枠あり(超過で課金)
セットアップGASのみで完結クラウド設定が必要
データ上限約500万セル実質無制限
同時アクセスLockServiceで排他制御ネイティブ対応
GUIでの編集スプレッドシートで直接編集可能管理コンソールが必要
向いている規模数百〜数千行数万行以上

完成すると、次の3つができるようになります。

  1. データの登録: スラッシュコマンドでスプレッドシートにデータを追加します(自動採番ID付き)
  2. データの照会: スラッシュコマンドでスプレッドシートのデータを一覧表示します
  3. 排他制御付き書き込み: LockServiceにより、複数ユーザーの同時書き込みでもデータが壊れません

準備・環境構築

環境構築とは、スプレッドシートのカラム設計とGASプロジェクトを準備する作業です。

準備項目取得方法備考
Discordアプリ・BotDeveloper Portalで作成スラッシュコマンド登録済みが前提
Bot Tokenアプリ設定 → Bot → Reset Token一度しか表示されないため必ず控える
Application IDアプリ設定 → General Informationコマンド登録APIに使用
GoogleスプレッドシートGoogle Driveで新規作成URLの /d//edit の間がスプレッドシートID

スラッシュコマンドの登録方法やBotのサーバー招待手順はDiscordスラッシュコマンド実装ガイドで解説しています。

スプレッドシートのカラム設計

スプレッドシートをデータベースとして使う場合、1行目にヘッダーを設定します。以下は在庫管理の例です。

ヘッダー説明
Aid数値自動採番の一意識別子
Bname文字列商品名
Cquantity数値在庫数
DcreatedAt日時登録日時(自動記録)

シート名は「在庫管理」とし、1行目にヘッダーを入力してください。

GASプロジェクトの作成

  1. Google Driveで「新規」→「その他」→「Google Apps Script」を選択します
  2. GASエディタの「プロジェクトの設定」→「スクリプトプロパティ」に以下を追加します
プロパティ名
DISCORD_BOT_TOKEN取得したBot Token
DISCORD_APPLICATION_ID取得したApplication ID
SPREADSHEET_IDスプレッドシートのID

スクリプトプロパティ(GASが提供する安全な設定値の保存機能)を使うことで、コードへのハードコードを防げます。 スプレッドシートIDやBot Tokenは必ずスクリプトプロパティに保存してください。

実装手順

実装手順とは、データ読み取り・データ追加・doPostハンドラーの3ステップでDiscord Botデータベース機能を完成させる作業です。 すべてのコードを1つのスクリプトファイルに貼り付けてください。

ステップ1 — データの読み取り(Read)

スプレッドシートからデータを読み取り、Discord上に一覧表示する関数を実装します。

function getSheet() {
  const sheetId = PropertiesService.getScriptProperties().getProperty('SPREADSHEET_ID');
  return SpreadsheetApp.openById(sheetId).getSheetByName('在庫管理');
}

function handleListCommand() {
  try {
    const sheet = getSheet();

    if (!sheet) {
      return createResponse('在庫管理シートが見つかりません');
    }

    const values = sheet.getDataRange().getValues();

    if (values.length <= 1) {
      return createResponse('在庫データがまだ登録されていません');
    }

    const lines = [];
    for (let i = 1; i < values.length; i++) {
      const id = values[i][0];
      const name = values[i][1];
      const quantity = values[i][2];
      lines.push('#' + id + ' ' + name + ': ' + quantity + '個');
    }

    const message = '**📦 在庫一覧**\n' + lines.join('\n');
    return createResponse(message);
  } catch (error) {
    Logger.log('在庫一覧エラー: ' + error.message);
    return createResponse('在庫データの取得中にエラーが発生しました');
  }
}

このコードのポイント:

  • getSheet()ヘルパー関数でスプレッドシートIDをスクリプトプロパティから取得しています
  • openById()を使うことで、Webアプリ(doPost)環境でも正しくシートを取得できます
  • データが0件の場合にも適切なメッセージを返しています

スプレッドシートの自動化について詳しくはGAS×スプレッドシート自動化をご覧ください。

ステップ2 — データの追加(Create + 排他制御)

LockService(GASが提供する排他制御の仕組み)を使って、複数ユーザーの同時書き込みでもデータが壊れない安全なデータ追加を実装します。

function handleAddCommand(options) {
  try {
    const name = options[0];
    const quantity = Number(options[1]);

    if (!name || isNaN(quantity) || quantity < 0) {
      return createResponse('入力形式: /add 商品名 数量(例: /add 商品A 50)');
    }

    const lock = LockService.getScriptLock();
    const locked = lock.tryLock(10000);

    if (!locked) {
      return createResponse('他のユーザーが書き込み中です。数秒後に再試行してください。');
    }

    try {
      const sheet = getSheet();

      if (!sheet) {
        return createResponse('在庫管理シートが見つかりません');
      }

      // 最終行のIDを取得して自動採番
      const lastRow = sheet.getLastRow();
      const newId = lastRow <= 1 ? 1 : Number(sheet.getRange(lastRow, 1).getValue()) + 1;

      sheet.appendRow([newId, name, quantity, new Date()]);

      return createResponse('✅ 登録しました: #' + newId + ' ' + name + '(' + quantity + '個)');
    } finally {
      lock.releaseLock();
    }
  } catch (error) {
    Logger.log('データ追加エラー: ' + error.message);
    return createResponse('データの追加中にエラーが発生しました');
  }
}

このコードのポイント:

  • LockService.getScriptLock()でスクリプト全体のロックを取得します
  • tryLock(10000)は最大10秒間ロック取得を待ちます。取得できない場合はユーザーにメッセージを返します
  • finallyブロックで必ずロックを解放し、デッドロックを防いでいます
  • 最終行のIDに+1して自動採番します。データが空の場合はID 1から開始します
  • 入力バリデーションで商品名と数量が正しく入力されているか確認しています

ステップ3 — doPostハンドラー

doPostとは、GASをWebアプリとしてデプロイした際にPOSTリクエストを受信する関数です。Discord Botからのインタラクション(コマンド操作)を受け取り、適切な処理に振り分けます。

function doPost(e) {
  try {
    const data = JSON.parse(e.postData.contents);

    // PING → PONG(Interactions Endpoint URL検証用)
    if (data.type === 1) {
      return ContentService.createTextOutput(
        JSON.stringify({ type: 1 })
      ).setMimeType(ContentService.MimeType.JSON);
    }

    // APPLICATION_COMMAND(スラッシュコマンド実行)
    if (data.type === 2) {
      const commandName = data.data.name;

      if (commandName === 'list') {
        return handleListCommand();
      }

      if (commandName === 'add') {
        const options = (data.data.options || []).map(function(opt) {
          return opt.value;
        });
        return handleAddCommand(options);
      }

      return createResponse('不明なコマンドです: /' + commandName);
    }

    return createResponse('処理できないリクエストです');
  } catch (error) {
    Logger.log('doPostエラー: ' + error.message);
    return createResponse('エラーが発生しました。管理者に連絡してください。');
  }
}

function createResponse(message) {
  return ContentService.createTextOutput(
    JSON.stringify({
      type: 4,
      data: { content: message },
    })
  ).setMimeType(ContentService.MimeType.JSON);
}

このコードのポイント:

  • data.data.optionsからスラッシュコマンドのオプション(引数)を取得しています
  • /listはデータ照会、/addはデータ追加に振り分けます
  • createResponse()ヘルパー関数でJSON形式のレスポンスを統一しています
  • doPostの実装パターンはDiscordスラッシュコマンド実装ガイドと共通です

動作確認・トラブルシューティング

動作確認とは、構築したデータ管理機能が期待どおりに動くかテストする作業です。

まずGASエディタの右上「デプロイ」→「新しいデプロイ」でWebアプリとしてデプロイします。 次にDiscordで/listを実行し、「在庫データがまだ登録されていません」と表示されることを確認します。 続いて/add 商品A 50を実行し、「登録しました」のメッセージが返ることを確認してください。

よくあるエラーと解決策

エラー・症状原因解決策
「在庫管理シートが見つかりません」シート名の不一致スプレッドシートのシート名が正確に「在庫管理」か確認
「他のユーザーが書き込み中です」LockServiceがロック中数秒後に再試行。頻発する場合はtryLockの待機時間を延長
「入力形式: /add 商品名 数量」コマンドの引数が不正数量は0以上の数値で入力。例: /add 商品A 50
401エラー(コマンド登録時)Bot Tokenが無効Developer PortalでTokenを再発行し、スクリプトプロパティを更新
データが二重登録されるロック取得前に複数リクエスト到着LockServiceの待機時間内に処理が完了しているか確認
「Exception: Invalid argument」SPREADSHEET_IDが未設定 or 無効スクリプトプロパティにIDが正しく設定されているか確認

GASエディタの「実行数」タブ(左メニュー)で過去の実行履歴とエラー内容を確認できます。

応用・カスタマイズ例

応用・カスタマイズとは、基本のCRUD機能をベースに業務シナリオを追加していくことです。

中小企業向けDiscordデータ管理シナリオ

シナリオコマンド例活用場面
在庫管理/add 商品A 50 /list入出庫の記録、在庫照会
問い合わせ管理/ticket 内容 /tickets顧客問い合わせの記録・一覧表示
タスク管理/task タスク名 /tasksチームのタスク登録・進捗確認

Webhookによる自動通知を組み合わせたい場合はDiscord Bot×GAS連携をご覧ください。

スプレッドシートDBの制限事項

運用前に以下の制限を把握しておきましょう。

制限事項上限対策
セル数上限約500万セル不要データの定期削除、シート分割
スクリプト実行時間6分/回大量データの一括処理は分割実行
同時書き込みLockServiceで排他制御高頻度アクセスにはCloud Firestoreを検討
読み取り速度行数に比例して低下1万行を超えたら本格DBへの移行を検討
Discordの応答制限3秒以内重い処理はDeferred Response(type 5)で対処

まとめ

GASとスプレッドシートを組み合わせれば、約60分・無料(2026年2月時点)でDiscord Botデータベース機能を構築できます。 LockServiceによる排他制御とエラーハンドリングにより、複数ユーザーが同時に使っても安全な運用が可能です。

GASの基礎から学びたい方はGAS入門ガイドをご覧ください。 Webhook通知を追加したい方はDiscord Bot×GAS連携をご確認ください。

よくある質問

スプレッドシートをデータベースとして使うのは安全ですか?

小規模なデータ管理には十分安全です。機密情報を扱う場合はスプレッドシートのアクセス権限を適切に設定し、共有範囲を限定してください。スクリプトプロパティでスプレッドシートIDを管理することで、コードからの情報漏洩も防げます。

スプレッドシートDBの同時書き込みは大丈夫ですか?

GASのLockServiceを使えば排他制御が可能です。この記事のコードではデータ追加時にスクリプトロックを取得し、同時書き込みによるデータ破損を防いでいます。高頻度の同時アクセスが継続的に発生する場合は、専用データベースへの移行を検討してください。

データ量が増えた場合の対処法は?

スプレッドシートは約500万セルが上限です。数千行のデータであれば問題なく動作します。1万行を超える場合はシートの分割や、Cloud FirestoreなどのNoSQLデータベースへの移行を検討しましょう。

スプレッドシートDBと本格的なデータベースはどちらを選ぶべきですか?

数百〜数千行のデータで、アクセス頻度が低〜中程度であればスプレッドシートDBで十分です。リアルタイム同期・大量データ・高頻度アクセスが必要な場合はCloud FirestoreやSupabaseなどの本格DBが適しています。この記事の制限事項表で判断基準を確認できます。

スプレッドシートDBのバックアップはどうしますか?

Googleドライブのバージョン履歴で過去のデータを復元できます。スプレッドシートの「ファイル」→「版の管理」から過去30日分の変更履歴を確認可能です。重要なデータは定期的にスプレッドシートをコピーしてバックアップすることも有効です。

関連記事