Googleフォームの回答ファイルを共有ドライブに保存(移動)させたい!/GAS(業務の話)

業務でGoogleツールに
お世話になることが多い今日この頃。

メールからチャットからカレンダー、
スプレッドシートにフォーム、ドライブ...

ある日とうとうGoogleAppsScript
(プログラミング)に手を出さなければならない
日が来てしまいました。

きっかけは、Googleフォームに送ってもらった
ファイルを共有ドライブに保存しなければ
ならなくなったこと。

フォームの回答は、テキストだけなら
書き出すスプレッドシートを共有ドライブに
用意しておけばよかったのですが、
ファイルは必ずマイドライブにしか入らず...

フォーム送信と同時に
共有ドライブに移動させるという
プログラムを書かないといけなくなりました。

エンジニアは周りに何人もいるんですが、
みんな定常業務に追われているので、
自分の勉強も兼ねてチャレンジすることに。


やったこと

・スプレッドシートに書き出されたフォームの一番新しい回答(テキスト)を、別途新たにスプレッドシートを生成して転記、ファイル(スプレッドシート)を共有ドライブに移動

・アップロードしてもらったファイルのIDを、回答が書き出されたスプレッドシートから切り出して取得、そのファイルを共有ドライブに移動

紆余曲折あり、結局

・回答は、予めスプレッドシート上で
関数を使い、新しい順&縦横入れ替えで
並べ替えておく

その範囲で新スプレッドシート作って転記、
移動
・ファイルはスプレッドシートに書き出された
リンクからID取得して移動

っていう手段で解決しました。

function autoCreateSheet(){
  const sheetId="スプレッドシートのID";
  const sheet=SpreadsheetApp.openById(sheetId);

//シート範囲取得
  const rangeValue=sheet.getRange('新しい順!A1:B27').getDisplayValues();

  //送信者氏名取得
  const name=sheet.getRange('新しい順!B3').getDisplayValue(); 

  //新シート作成
  const newSheet=SpreadsheetApp.create(name);
  const newSheetRange=newSheet.getRange('A1:B27').setValues(rangeValue);
  const newSheetId=newSheet.getId();

//移動先フォルダ
  const toFolderId='移動先フォルダのID';
  const toFolder=DriveApp.getFolderById(toFolderId);
  const personalFile=DriveApp.getFileById(newSheetId);
  personalFile.moveTo(toFolder);

   //ファイル移動
  const frontUrl=sheet.getRange('新しい順!B26').getDisplayValue();
  const index="=";
  const frontIdSeparate=frontUrl.split(index);
  const frontId=frontIdSeparate[1];
  const frontFile=DriveApp.getFileById(frontId).setName((name)+"【表】");
  frontFile.moveTo(toFolder);

  const backUrl=sheet.getRange('新しい順!B27').getDisplayValue();
  const backIdSeparate=backUrl.split(index);
  const backId=backIdSeparate[1];
  const backFile=DriveApp.getFileById(backId).setName((name)+"【裏】");
  backFile.moveTo(toFolder);
 
}

最初に

プログラムは、回答を書き出されるスプレッドシートから
拡張機能>AppsScript
を開いて書きました。

そして、回答ごとにnewスプレッドシートを
生成した理由なんですが...

そもそもフォームの回答は、
あくまで入力してもらった情報。

その後変更があっても、直接いじることはできないので、
データ保管には使えません...

でもそれだととんでもなく不便なので、
変更/修正できるようにしたってところです。

どのみちフォーム送信時、一番新しい情報を書き出したいので、
スプレッドシート上で先に新しい順に並べ替え、
ついでに見やすいように縦横並べ替えた状態で、
そのまま新シートに転記するようにしました。

スプレッドシート上の関数は、
=TRANSPOSE(sort('回答'!A2:AA,1,false))

sortでタイムスタンプ順に並べ替え、
基準になるタイムスタンプは1列目なので1、falseは降順。
TRANSPOSEで行と列の縦横を逆に。

(A2:AAのところは任意の範囲で!)

多分getLastRowとか使って
最終行取得とかでできなくもないですが、
フォームの回答って横に羅列されて長くなって
結局見づらいじゃないですか。

ってことで先にスプレッドシートを
細工するっていう手段に出ました。

そしたら、プログラム上では毎回
同じ範囲を取得すればよいので
難しいことを考えなくてよい。

初心者なのでこのくらい
ハードルを下げて挑戦しました。

トップに戻る↑

IDからスプレッドシートを取得

 const sheetId="スプレッドシートのID";
  const sheet=SpreadsheetApp.openById(sheetId);

スプレッドシートを開いていない時に
動いてほしいプログラムなので
(もはやいちいち開きたくない)、
アクティブなシート取得ではなく、
IDから絶対的に取得させます。

スプレッドシートのIDは、
開いて表示されている時のリンクを見て、
sheet/d/の先から、/editまでのスラッシュの間です。
(伝えづらい!!)

docs.google.com/spreadsheets/d/AsdfghJklZxcvbNmQwertYuiopAsdfghjkl/edit#gid=123123123

↑のマーカーついてるとこです。
(値はダミーです)

const sheetId='AsdfghJklZxcvbNmQwertYuiopAsdfghjkl';
で、これからsheetIdって言えばこれだよ!と宣言。

SpreadsheetApp.openByIdで、
宣言したIDからスプレッドシートを取得。

トップに戻る↑

//シート範囲取得

const rangeValue=sheet.getRange('新しい順!A1:B27').getDisplayValues();

「sheet」が取得したスプレッドシート
(Spreadsheetオブジェクト)になります。

スプレッドシートの中の、
取得したい範囲(=あとで書き出したい範囲)を
getRange('シート名!範囲:範囲')
で取得。

そこに表示されてるテキストを取得したいので、
getDisplayValue()

一個ずつ宣言しながら書いてたんですが、
長くなっちゃったので.(ドット)でつないで
少しだけ短くしました。

ここから先は、rangeValueと言われたら、
一番新しい、あとで書き出したい情報の
テキストたちのことです。

トップに戻る↑

//送信者名取得

const name=sheet.getRange('新しい順!B3').getDisplayValue();

これは普通に入力してもらったテキストを
取得しているだけです。

後で作ったスプレッドシートや、
送信してもらったファイルに
入力してもらった名前を付けたくて
取得しています。

送信されたファイルには、
googleアカウントの名前がついてくれるんですが、
本名と一致しなかったり、その後何かと
不便が生じたので、統一をはかった次第です。

ここから先は、nameと言われたら
入力してもらった名前のことです。

トップに戻る↑

//新シート作成

const newSheet=SpreadsheetApp.create(name);
  const newSheetRange=newSheet.getRange('A1:B27').setValues(rangeValue);
  const newSheetId=newSheet.getId();

SpreadsheetApp.create(name)
”name”のところには任意の名前をつけられ、
テキストで指定する場合は””でくくります。

私は入力してもらった名前をそれぞれつけたかったので、
一個前で取得したnameを使いました。

そして、書き出したい範囲として取得したのと
同じ範囲を指定、
元の回答書き出しシートで
取得していたテキストをsetValues(rangeValue)で
新しいシートに転記します。

あとで共有ドライブに移動させたいので、
ついでにIDも「getId()」で取得しておきます。

ここから先は、「newSheetId」と言われたら
新しく作って情報書き出したスプレッドシートの
IDだよってことになりました。

トップに戻る↑

//移動先フォルダ

const toFolderId='移動先フォルダのID';
  const toFolder=DriveApp.getFolderById(toFolderId);
  const personalFile=DriveApp.getFileById(newSheetId);
  personalFile.moveTo(toFolder);

作ったシートや、送信してもらったファイルを
移動させる先の共有ドライブフォルダを宣言して、
さっき作った新しいスプレッドシートを
移動させています。

フォルダの取得も、考え方は最初にIDから
スプレッドシートを取得したときとおんなじ。

フォルダのIDは、フォルダを開いて、
表示されているリンクのfolders/
から先です。

toFolderIdと言われたら、
フォルダのIDだよってことにして、
それをもとにgetFolderById(toFolderId)で
移動先のフォルダを取得。

そいつをtoFolderと呼ぶことにします。

さっき作ったスプレッドシートのIDを
newSheetIdにしておいたので、それをもとに
getFileById(newSheetId)で新しくできたやつを取得、
personalFileと呼ぶことにします。

それをmoveTo(toFolder)でフォルダに移動。

toFolderは移動先のフォルダでしたね。

トップに戻る↑

//ファイル移動

const frontUrl=sheet.getRange('新しい順!B26').getDisplayValue();
  const index="=";
  const frontIdSeparate=frontUrl.split(index);
  const frontId=frontIdSeparate[1];
  const frontFile=DriveApp.getFileById(frontId).setName((name)+"【表】");
  frontFile.moveTo(toFolder);

フォームの回答にアップロードしてもらった
ファイルも共有ドライブに移動させたいのですが、
これを取得するのにとっても難儀しました。

結局、リンクを書き出されたスプレッドシートから
IDをどうにか抜き出して絶対的に取得、
そいつを移動させる手段で解決しました。

そもそものおなはし、
フォルダやファイルを探して取得するには、
プログラムを書く場所をスプレッドシートからでなく、
マイドライブから新規(+)>その他>AppsScript
から開かないと不可能だったんですが、
それに気づくのに2週間くらいかかりました...

二つアップロードしてもらうので、
同じこと二回書いてます。

まずは、表示されているリンク(テキスト)を
今までと同じように取得。

const frontUrl=sheet.getRange('シート名!セル番号').getDisplayValue();

リンクをfrontUrlと呼ぶことにして、
ひとまず表示されているテキストを
取得しています。

そしてそのリンクをよくよく見ると、
「=」から先がIDになっている...

ここで分割してIDからファイルを
絶対的に取得しようと思います。

まずは目印になる「=」を、
indexと呼ぶことにします。

const index="=";

そしてsplitを使って、二つに分割します。

const frontIdSeparate=frontUrl.split(index);

ほかにsliceとかあったんですが、
それだと「=」まで含まれてしまって
IDだけ切り抜けなかったので、
splitを使いました。

二つに分かれた文字列は、
[0]番目と[1]番目になっていて、
後ろ側が欲しいので[1]だけを指定。

frontIdと呼ぶことにします。

const frontId=frontIdSeparate[1];

あとはそれをもとにして
IDからファイルを絶対的に取得、
作ってたname使って名前を付けて(オプション)
moveToで同じように移動させるだけ。

const frontFile=DriveApp.getFileById(frontId).setName((name)+"【表】");
frontFile.moveTo(toFolder);

トップに戻る↑


てな感じで、入力&アップロードしてもらったものを
共有ドライブに保存(実態は移動)することができました。

こんな書き方で伝わったでしょうか...

まだ繰り返しとか条件分岐とか、
プログラムっぽいプログラムには
手を出していないのでそこまで複雑でないですが、
基本的な考え方は理解できたかな...と思います。

本見てお勉強するより、
実際触って動かした方が身につくので、
是非挑戦しましょう^^

私も他にプログラム化したいものあるので
頑張ります...

ということで、今回はこの辺で!

この記事の投稿者

入社半年の採用アシスタント兼広報担当。
学歴高卒/完全未経験で拾っていただき、日々勉強しながら&調べながら発信中。
とりあえずITパスポートは入社後3週間ちょいで取得済。
最近は開発部門のテスト作業も手伝わせてもらえることに。
趣味は絵(アナログ)とカラオケ(週1~)と自転車(眺める専)、九州の実家には拾った猫3匹&カメ1匹が鎮座。