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

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

ただいまの
回答率

89.96%

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 488

efuji

score 5

前提・実現したいこと

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
などを見たのですが、私の技量では理解できませんでした。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hiroshi0240

    2019/06/19 14:34

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

    キャンセル

  • papinianus

    2019/06/19 18:20

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

    キャンセル

  • efuji

    2019/06/20 10:22

    >要は「 var files = targetFolder.getFiles();」のタイミングでそのフォルダ配下の全フォルダ及び
    >ファイルを取得する方法を知りたいという理解で良いですか?
    フォルダ配下のファイルが取得できれば、取得のタイミングはいつでも構わないと考えています。

    >どこでどういうトリガを仕掛けて実行しているのでしょうか?
    プロジェクトのトリガーの設定から、時間主導>分タイマー で実行しています。

    キャンセル

回答 2

checkベストアンサー

+1

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

var lastUpdateMap = {};

function filesearch(TARGET_FOLDER_ID) {  
  var files = DriveApp.searchFiles("'" + TARGET_FOLDER_ID + "' in parents");
  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());
  }  
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/04 16:06

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

    キャンセル

  • 2019/07/04 18:56

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

    キャンセル

  • 2019/07/08 15:59 編集

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

    キャンセル

+1

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

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

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(TARGET_FOLDER_ID); // // // // //

    // スプレッドシートに記載されているファイル名と更新日時を取得。
    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"
            );
        });
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/07/08 15:57

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

    キャンセル

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

  • ただいまの回答率 89.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる