Open21

GASいろいろ

shotakahashotakaha

ファイルを読み込む

  • IDもしくはURLを指定してファイルを読み込む
const book = SpreadsheetApp.openById("スプレッドシートのID";
const docs = DocumentApp.openByUrl("ドキュメントのURL");
  • スクリプトに紐づいたファイルを読み込む
const book = SpreadsheetApp.getActiveSpreadsheet();
const sheet = SpreadsheetApp.getActiveSheet();
shotakahashotakaha

新規作成する

const book = SpreadsheetApp.create("新しいスプレッドシート名");

// 新規に作成したURLとIDを確認
const bookUrl = book.getUrl();
const bookId = book.getId();
  • createで新しいスプレッドシートを作成できる
  • getUrlgetIdで新しく発行された情報を取得できる
shotakahashotakaha

ログを出力する

  • Logger.logconsole.log の2種類ある
  • ちょっと使うだけならどっちでもよさそう
Logger.log("ログです")
console.log("ログです")
shotakahashotakaha
  • Logger.logの場合は「情報」(infoのこと?)と表示される
  • console.logの場合は「デバッグ」と表示される
shotakahashotakaha

スプレッドシート内のシートを取得する

  • 全てのシートが欲しい時には getSheets が便利
const book = SpreadsheetApp.openById("ID");
// ブック内のシートを配列として取得
const sheets = book.getSheets();

// シート数を確認
Logger.log(`シート数 =  ${sheets.length}`);

// シートごとの名前を確認
for (const sheet of sheets) {
    Logger.log("シート名 = " + sheet.getName());
}
  • シート名を指定する
const book = SpreadsheetApp.getActiveSpreadsheet();
const sheet = book.getSheetByName("シート名");
shotakahashotakaha

シートをコピーする

  • 別のスプレッドシートにコピーする
// ブックを開く
const source = SpreadsheetApp.openById("コピー元のID");
const target = SpreadsheetApp.openById("コピー先のID");

// コピーしたいシートを取得
const sheet = source.getSheetByName("シート1");
// シートをコピー(してコピーしたシートを取得)
const copied = sheet.copyTo(target);

Logger.log(`シート名= ${copied.getName()}`);
// シート名 = シート1のコピー
  • 別のスプレッドシートにコピーしても「シート1のコピー」というシート名になる
  • 繰り返すと「シート1のコピー2」「シート1のコピー3」...となる
shotakahashotakaha

シートを削除する

  • 上の続き
  • リファレンスを確認すると deleteSheet(sheet) となっている
    • シート名ではなくてsheetオブジェクトを作る必要がある
    • スプレッドシート内のシートが0になる場合はエラーになる
const target = SpreadsheetApp.openById("コピー先のID");
target.deleteSheet(target.getSheetByName("シート1のコピー");

できるかなと思ったけどできなかったこともメモ

  • またやりそうなのでメモ
target.getSheetByName("シート1のコピー").deleteSheet();  // このメソッドはない
target.deleteSheet("シート1のコピー"); // このメソッドもない
shotakahashotakaha

ブックを削除する

const file = DriveApp.getFileById("削除したいID");
file.setTrashed(true);
  • スプレッドシート全体を削除する場合、DriveAppからファイルオブジェクトを取得する
  • ファイルオブジェクトをゴミ箱に移動する(30日後に自動削除)
shotakahashotakaha

フォームと自動通知

  • Googleフォームに入力があったときに、任意の関係者に自動で通知をする
  • 自分のGmailから、関係者を指定してメールを送信する形式
autoForward.js
function onFormSubmit(e) {

    // フォームの入力情報を取得する
    const timestamp = e.response.getTimestamp();
    const respondent = e.response.getRespondentEmail();
    
    // フォームの回答を取得
    const itemResponses = e.response.getItemResponses();
    const values = itemResponses.map(function(itemResponse) {
        return itemRespons.getResponse()
    });

    const purpose = values[1];
    const date_start = values[7];
    const date_end = values[8];

    // メールの本文を作成する
    const body = `
Googleフォームに申請がありました。
関係者への確認をお願いします。

# 申請日
${timestamp}

# 申請者
${name}

# 掲載期間
開始希望日 ${date_start}
終了希望日 ${date_end}
`

    // メールの件名を作成する
    const subject = `フォームに申請(${name}`;

    // メールを作成する
    const to = "関係者1,関係者2,関係者3";
    const draft = GmailApp.createDraft(to, subject, body);
    draft.sent();    
}
shotakahashotakaha
autoForward.js
function onFormSubmit(e) {
    const timestamp = e.response.getTimestamp();
    const respondent = e.response.getRespondentEmail();
};
  • eはトリガーした「イベント」のようなオブジェクトと考えてよさそう
  • メール通知に必要はデータはe.responseの中にある
  • フォームの回答内容はe.response.getItemResponses()に入っている
shotakahashotakaha
autoForward.js
    // フォームの回答を取得
    const itemResponses = e.response.getItemResponses();
    const values = itemResponses.map(function(itemResponse) {
        return itemResponse.getResponse()
    });
  • 以前は e.valuesという値があったみたいだが、いまはundefinedと言われる
  • 自分でそれっぽい配列valuesを作成している
  • GAS(or JS)の書き方が全然分かってないんだけど、Pythonのリスト内包表記と同じ形式だと思っている
Pythonのリスト内包表記
values = [itemResponse.getResponse() for itemResponse in e.response.itemResponses()]
shotakahashotakaha
autoForward.js
    ....
    const purpose = value[1];
    ....
    const date_start = value[7];
    const date_end = value[8];
    ....
  • 回答データの配列valuesから、わかりやすい変数名に代入する
  • 自分の作ったフォームに合わせて、変数を用意する
shotakahashotakaha
autoForward.js
    ...
    // メールの本文を作成する
    const body = `
Googleフォームに申請がありました。
関係者への確認をお願いします。

# 申請日
${timestamp}

# 申請者
${name}

# 掲載期間
開始希望日 ${date_start}
終了希望日 ${date_end}
`
    ...
  • メール本文を作成する
  • 文字列テンプレートを使って、さきほど詰め直した変数を使う
  • 実際の際のメールにインデントも反映されるので、左詰めにしておく
shotakahashotakaha
autoForward.js
    // メールの件名を作成する
    const subject = `フォームに申請(${name}`;

    // メールを作成する
    const to = "関係者1,関係者2,関係者3";
    const draft = GmailApp.createDraft(to, subject, body);
    draft.send();  
  • メールの下書きを作成してから送る
  • 複数の宛先に送る場合はカンマで区切る
  • 初めて実行する場合には、アプリ権限の許可が必要になる
shotakahashotakaha
  • フォームの送信をトリガーとするのでデバッグがめんどくさかった
  • すべてが空欄でも送信できるテスト用フォームを新規に作成しe.response のデータを確認しながらデバッグした
  • e.valuesという変数が残っていれば、もっと簡単だった
shotakahashotakaha
このアイテムは Google の利用規約に違反しているため、アクセスできません。
  • 動作確認に使っていたフォームがアクセス禁止になってしまったっぽい
  • 短い時間に何度もフォームに入力して、メールを送ったりしたからかな?
  • 次にやるときは注意した方がよさそう
shotakahashotakaha

シートにあるデータを選択

const book = SpreadsheetApp.getActiveSpreadsheet();
const sheet = book.getActiveSheet();
const range = sheet.getDataRange();
const rows = range.getValues();

// 最初は見出し行(であることが多いはず)
const headers = rows[0];
const data = rows.slice(1);
  • データの範囲を数値で指定
const nrows = sheet.getLastRow();
const ncols = sheet.getLastColumn();
const range = sheet.getRange(1, 1, nwors, ncols);
shotakahashotakaha

ファイル名を変更したい

/**
 * @param {string} id - スプレッドシートID
 */
function renameBook(id) {
  // IDを指定してスプレッドシートを取得
  const book = SpreadsheetApp.openById(id);
  
  // 現在のファイル名を取得
  // 20241115_ファイル名 の形式
  const currentName = book.getName();
  
  // YYYYMMDD_ を削除 => 8桁の数字
  const stem = currentName.replace(/^\d{8}_/, "");
  
  // 現在時刻を取得
  // 20241119
  const now = new Date();
  const jst = Utilities.formatDate(now, "JST", "yyyyMMdd");
  
  // 新しいファイル名
  // 20241119_ファイル名
  const newName = `${jst}_{stem}`
  
  // ファイル名を変更する
  book.rename(newName)

  return book;
}
  • ファイル名の先頭に日付(yyyyMMdd)を付与しておくと、あとから探しやすい
  • 更新した場合は、ファイル名も現在時刻にしたい
  • ただ閲覧したときに更新してほしくないので、onEditなどは不向き
  • 意図をもって更新した場合に、ファイル名を変更したいので、メニューにカスタムボタンを追加するのがいいのかもしれない