質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

2回答

2415閲覧

Google Apps Scriptでサブフォルダ内のファイルもアップデート検知したい

efuji

総合スコア12

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

0グッド

0クリップ

投稿2019/06/19 04:39

編集2019/07/04 07:05

前提・実現したいこと

Google Apps sctiptでファイルが追加されたことをメールで通知が来るように
したいと考えています。

発生している問題・エラーメッセージ

指定フォルダ内へのファイル追加については問題なく検知できるのですが、
サブフォルダの検知ができません。
サブフォルダまで検索してアップデート日、ファイル名を取得するにはどうすればよいでしょうか?

該当のソースコード

var TARGET_FOLDER_ID = "xxx"; var UPDATE_SHEET_ID = "xxxx"; var UPDATE_SHEET_NAME = "sheet"; var SEND_MAIL_ADDRESS = ["xxx@xxx"] function updateCheck() { // 対象フォルダ配下のファイル最終更新日時を取得。 var lastUpdateMap = {}; function filesearch(TARGET_FOLDER_ID) { var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID); var files = targetFolder.getFiles(); while (files.hasNext()) { var file = files.next(); lastUpdateMap[file.getName()] = file.getDateCreated(); } var folders = DriveApp.searchFolders("'" + TARGET_FOLDER_ID + "' in parents"); while (folders.hasNext()) { var folder = folders.next();    lastUpdateMap[folder.getName()] = folder.getDateCreated(); filesearch(folder.getId()); } } filesearch(); // スプレッドシートに記載されているファイル名と更新日時を取得。 var spreadsheet = SpreadsheetApp.openById(UPDATE_SHEET_ID); var sheet = spreadsheet.getSheetByName(UPDATE_SHEET_NAME); var data = sheet.getDataRange().getValues(); // 取得したデータをMapに変換。 var sheetData = {}; // 説明とヘッダを記載しているため2からstart。 for (var i = 2; i < data.length; i++) { sheetData[data[i][0]] = {name : data[i][0], lastUpdate : data[i][1], rowNo : i + 1}; } // 実際のファイルとスプレッドシート情報を比較。 var updateFolderList = []; for (key in lastUpdateMap) { if(key in sheetData) { // ファイル名がシートに存在する場合。 if(lastUpdateMap[key] > sheetData[key].lastUpdate) { // フォルダが更新されている場合。 sheet.getRange(sheetData[key].rowNo, 3).setValue(lastUpdateMap[key]); updateFolderList.push(key); } } else { // ファイル名がシートに存在しない場合。 sheet.getRange(sheet.getLastRow() + 1, 1).setValue(key); sheet.getRange(sheet.getLastRow(), 3).setValue(lastUpdateMap[key]); updateFolderList.push(key); } } // 新規及び更新された情報をメール送信。 if (updateFolderList.length != 0) { SEND_MAIL_ADDRESS.forEach(function(o,i) { MailApp.sendEmail(SEND_MAIL_ADDRESS[i],"追加通知", "写真が追加されました。" + "\n" + "追加されたファイルは以下の通りです。" + "\n" + updateFolderList.join("\n") + "\n\n" ); }); } }

試したこと

https://ctrlq.org/code/20034-search-drive-files
https://stackoverflow.com/questions/36577071/search-files-inside-sub-folders-in-google-drive
などを見たのですが、私の技量では理解できませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroshi0240

2019/06/19 05:34

コードには他にも気になることはいくつかありますが、要は「 var files = targetFolder.getFiles(); 」のタイミングでそのフォルダ配下の全フォルダ及びファイルを取得する方法を知りたいという理解で良いですか?
papinianus

2019/06/19 09:20

後学のために伺いたいのですが、どこでどういうトリガを仕掛けて実行しているのでしょうか?
efuji

2019/06/20 01:22

>要は「 var files = targetFolder.getFiles();」のタイミングでそのフォルダ配下の全フォルダ及び >ファイルを取得する方法を知りたいという理解で良いですか? フォルダ配下のファイルが取得できれば、取得のタイミングはいつでも構わないと考えています。 >どこでどういうトリガを仕掛けて実行しているのでしょうか? プロジェクトのトリガーの設定から、時間主導>分タイマー で実行しています。
guest

回答2

0

filesearch(TARGET_FOLDER_ID); // // // // //
ここじゃないですかね。

DriveApp.getFolderById(TARGET_FOLDER_ID);を関数の外にだすと、グローバルのvar TARGET_FOLDER_IDで解決されて正常に動作します。
これを関数の中に入れるとfunction filesearch(TARGET_FOLDER_ID) {の仮引数でマスクされて、グローバルを指さなくなります。
最初に書いたところは質問者様は、実引数なし()にしているので関数内部でTARGET_FOLDER_IDundefined。そのようなidのフォルダがないのでエラー。

javascript

1var TARGET_FOLDER_ID = "xxx"; 2var UPDATE_SHEET_ID = "xxxx"; 3var UPDATE_SHEET_NAME = "sheet"; 4var SEND_MAIL_ADDRESS = ["xxx@xxx"] 5 6function updateCheck() { 7 // 対象フォルダ配下のファイル最終更新日時を取得。 8 var lastUpdateMap = {}; 9 10 function filesearch(TARGET_FOLDER_ID) { 11 var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID); 12 var files = targetFolder.getFiles(); 13 while (files.hasNext()) { 14 var file = files.next(); 15 lastUpdateMap[file.getName()] = file.getDateCreated(); 16 } 17 var folders = DriveApp.searchFolders("'" + TARGET_FOLDER_ID + "' in parents"); 18 while (folders.hasNext()) { 19 var folder = folders.next(); 20 lastUpdateMap[folder.getName()] = folder.getDateCreated(); 21 filesearch(folder.getId()); 22 } 23 } 24 25 filesearch(TARGET_FOLDER_ID); // // // // // 26 27 // スプレッドシートに記載されているファイル名と更新日時を取得。 28 var spreadsheet = SpreadsheetApp.openById(UPDATE_SHEET_ID); 29 var sheet = spreadsheet.getSheetByName(UPDATE_SHEET_NAME); 30 var data = sheet.getDataRange().getValues(); 31 32 // 取得したデータをMapに変換。 33 var sheetData = {}; 34 // 説明とヘッダを記載しているため2からstart。 35 for (var i = 2; i < data.length; i++) { 36 sheetData[data[i][0]] = {name : data[i][0], lastUpdate : data[i][1], rowNo : i + 1}; 37 } 38 39 // 実際のファイルとスプレッドシート情報を比較。 40 var updateFolderList = []; 41 for (key in lastUpdateMap) { 42 if(key in sheetData) { 43 // ファイル名がシートに存在する場合。 44 if(lastUpdateMap[key] > sheetData[key].lastUpdate) { 45 // フォルダが更新されている場合。 46 sheet.getRange(sheetData[key].rowNo, 3).setValue(lastUpdateMap[key]); 47 updateFolderList.push(key); 48 } 49 } else { 50 // ファイル名がシートに存在しない場合。 51 sheet.getRange(sheet.getLastRow() + 1, 1).setValue(key); 52 sheet.getRange(sheet.getLastRow(), 3).setValue(lastUpdateMap[key]); 53 updateFolderList.push(key); 54 } 55 } 56 57// 新規及び更新された情報をメール送信。 58 if (updateFolderList.length != 0) { 59 SEND_MAIL_ADDRESS.forEach(function(o,i) { 60 MailApp.sendEmail(SEND_MAIL_ADDRESS[i],"追加通知", 61 "写真が追加されました。" + "\n" + 62 "追加されたファイルは以下の通りです。" + "\n" + 63 updateFolderList.join("\n") + "\n\n" 64 ); 65 }); 66 } 67}

投稿2019/07/04 12:43

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

efuji

2019/07/08 06:57

ありがとうございます!この場合、実行時に引数渡さなきゃですね。無事動作しました。
guest

0

ベストアンサー

lastUpdateMapに配下のすべてのフォルダとファイルの情報が入るように再帰的に書いて見ました。

GAS

1var lastUpdateMap = {}; 2 3function filesearch(TARGET_FOLDER_ID) { 4 var files = DriveApp.searchFiles("'" + TARGET_FOLDER_ID + "' in parents"); 5 while (files.hasNext()) { 6 var file = files.next(); 7 lastUpdateMap[file.getName()] = file.getDateCreated(); 8 } 9 var folders = DriveApp.searchFolders("'" + TARGET_FOLDER_ID + "' in parents"); 10 while (folders.hasNext()) { 11 var folder = folders.next(); 12   lastUpdateMap[folder.getName()] = folder.getDateCreated(); 13 filesearch(folder.getId()); 14 } 15}

投稿2019/06/19 05:54

hiroshi0240

総合スコア640

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

efuji

2019/06/20 02:43 編集

ありがとうございます! しかし、filesearch() 関数を走らせると "while (files.hasNext()) {"に対して、「指定された ID のアイテムは見つからなかったか、アクセスする権限がありません。」というエラーが出てしまいました。
hiroshi0240

2019/06/21 07:30

フォルダの中にファイルが存在しないものがあるとそうなっちゃいますね。その場合は、filesイテレータにデータがない時のエラー処理を追記すれば良いと思います。
efuji

2019/06/24 00:11

なるほど。確かにそうですね。 しかし、空のフォルダがない状態でもやはり同じエラーとなってしまいました。
hiroshi0240

2019/06/24 09:56

一応確認です。filesearch() 関数の()内のパラメータに使用するフォルダのID var TARGET_FOLDER_ID = "xxxxx"; は正しく(自分の権限で閲覧可能なフォルダのIDが)入っていますよね。
efuji

2019/06/25 00:28

はい、IDに間違いはありませんでした。 再度、 while (files.hasNext()) { var file = files.next(); lastUpdateMap[file.getName()] = file.getDateCreated(); } で動作させると、エラーなく、指定フォルダ直下のファイル名・作成日は取得できました。 教えていただいた関数にするとエラーが出てしまいます。
hiroshi0240

2019/06/25 02:01

では、 var files = DriveApp.searchFiles("'" + TARGET_FOLDER_ID + "' in parents");の部分を var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID); var files = targetFolder.getFiles();に置き換えて見てください。
efuji

2019/06/26 04:47

たびたび、ありがとうございます。 DriveApp.をfilesearch(){}内で行うとエラーが出るようです。なぜでしょうね。。 filesearch()の外で、var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID);、 filesearch()内で var files =targetFolder.getFiles(); while... ..... var folders = targetFolder.getFolders(); ... としたところ、エラーは出なかったのですが処理が完了せずタイムアウトとなりました。 今のところ、指定フォルダ内にはフォルダ数は3つ、それぞれの内部に3~5のファイルがあるだけです。 var files = DriveApp.searchFiles("'" + TARGET_FOLDER_ID + "' in parents");などもfilesearch()の外で宣言するとエラーなく実行できましたが、これでは指定フォルダ直下の内容しか取得できませんよね(念のため.logも見てみましたが直下の内容のみでした)。
hiroshi0240

2019/06/26 06:13

私のお渡ししたものは、再帰的にFolderIDから対象ファイルを読み込むので、そとでフォルダーを定義すると同じ処理がループしてタイムアウトになるはずです。fileserch()関数のカッコ内のパラメータでフォルダのIDを都度受け取って対象フォルダが可変できる形で直してください。
efuji

2019/06/26 06:59

あぁ、そうですね。わたしの理解不足で申し訳ありません。 function filesearch(TARGET_FOLDER_ID) { var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID); var files = targetFolder.getFiles(); でもやはりtargetFolderの行でエラーとなってしまいます。 なぜfilesearch()内ではエラーとなってしまうのでしょう。
hiroshi0240

2019/07/03 11:19

他の回答者さんからも回答もらえるように、一旦ここまで書かれたコード全体をアップしてみて下さい。現状コメントからでは問題箇所が見えません
efuji

2019/07/04 07:06

アドバイス、本当にありがとうございます。 現在のコードに更新しました。
hiroshi0240

2019/07/04 09:56

わかりました。すみません。自分で書いておきながら引数を渡す必要が有ることを失念していました。 ファンクション名で引数を2つもらうように「function filesearch(lastUpdateMap,TARGET_FOLDER_ID)」として実行呼び出しの「filesearch(folder.getId())」部分も、「filesearch(lastUpdateMap,folder.getId())」としてください。同様にご自身で記載されている。「filesearch()」部分も「filesearch(lastUpdateMap,TARGET_FOLDER_ID)」と記載してください。
efuji

2019/07/08 07:03 編集

ありがとうございます!実行呼び出し側から引数を渡さなきゃですね。無事動作しました。papinianus様の回答も非常に助かりましたが、hiroshi0240様には長い間、丁寧にご対応いただきましたので、ベストアンサーに選ばせていただきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問