【GAS】GoogleClassroomの取得上限以上のリストを取り出す方法(nextPageToken)


こんにちは!GoogleAppsScriptを使った業務効率化に夢中の初心者プログラマー、太郎です。

今日はGoogleClassroomの取得上限以上のリストを取り出す方法について書いていきたいと思います。

初心者向けですが、javascriptの基本的なルールは押さえておいた方が理解はしやすいと思いますので、まだの方はProgateでサクッとjavascriptの文法を学習してみてください。

また、ReferenceError: Classroom is not definedとエラーが出てしまった方は、こちらの記事を参考にしてみてください。
では、早速トライしていきましょう!

GoogleClassroomで一度に取得できるリスト上限は30

前回の記事で、Classroomに所属している生徒の一覧を取得する方法について書いたのですが、どうもこのやり方だと、Classroomでは30人分までしかデータを取得できないことが分かりました。

let studentList = Classroom.Courses.Students.list(courseId);

所属が30以上いるクラスの場合は、違うやり方をしないといけなさそうですね。ちなみに、確認はしていないのですが、教師のリストや配布した課題のリストを取得する際にもこの上限が適応されるみたいです。
公式ドキュメントを見てみるとリストを呼び出す際の上限が設定できそうなpageSizeというパラメーターを発見!おっ、これは行けるかもと、こんな風に書き換えて実行してみると、、、

let studentList = Classroom.Courses.Students.list(courseId, {"pageSize": 1000);

はい、これでもダメでしたね。よくよく読むと
The server may return fewer than the specified number of results.
サーバーは指定された値よりも小さい値を返すかも(テヘペロ)
と書いてありますね。(いやっテヘペロは書いてない。。。)

「いや、『かも』って何だよ!というかテヘペロすんな!!!」と初心者にはまったく優しくない公式ドキュメント様に不満をぶつけつつ(いやっ、、、だからテヘペロは書いてない。。。)、他の方法を探してみると、どうもpageTokenというパラメーターが鍵になっているようです。

pageTokenとは?

pageTokenとは、簡単に言えば本のしおりみたいなもの。「ここからデータを取得するよ~~~」と教えてくれるパラメーターです。
デフォルトではnullに設定されています。

let studentList = Classroom.Courses.Students.list(courseId);
Logger.log(students.pageToken);//「null」が出力される

ただ、空の値を代入して設定するのが通常みたいですね。こんな風に書いてある例が多いです。

let pageToken = "";
let studentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);

なんとなく仕組みが分かった気がするのでこんな風に書いてみると、、、

let pageToken = "";
let firstStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
let secondStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);

はい、firstStudentListsecondStudentListには全く同じ情報が格納されます、笑。どちらも0ページ目から30ページ目の情報が入ってしまうんですね。

nextPageTokenでしおりを『挟む』

実は、pageToken本のしおりの位置を教えてくれるだけで、しおりを挟んでくれるわけではないんですね。しおりを挟むために重要なのが、「ここまで読んだ!」という情報を教えてくれる、nextPageTokenというパラメーターです。

このnextPageTokenは、一度リスト取得を実行すると、自動で設定されます。

let pageToken = "";
let firstStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
Logger.log(firststudentList.nextPageToken);//「なんか長い文字列」が出力されるはずです。

この『ここまで読んだよ』情報=nextPageToken『この位置から読み始めるよ情報』=pageTokenの値に設定してあげれば、ようやくしおりが挟めます。

let pageToken = "";
let firstStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
pageToken = firstStudentList.nextPageToken;//しおりを挟む!

こうですね!
このpageTokenを次の呼び出し時に使えば、前回の続きからデータを取得できます。

let pageToken = "";
let firstStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
pageToken = firstStudentList.nextPageToken;//しおりを挟む!(1回目)
let secondStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
pageToken = secondStudentList.nextPageToken;//しおりを挟む!(2回目)
let thirdStudentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
pageToken = thirdStudentList.nextPageToken;//しおりを挟む!(3回目)
//・・・以下繰り返し

このようにpageTokennextPageTokenを使えば、Classroomの上限数30を超えてリストを取得できます。
もちろん、上の記述ではダサいので、繰り返しの処理してあげる必要があります。

do{} whileを使う

いろいろ調べてみたのですが、今のところdo {} whileのメソッドを使った書き方が一番しっくり来たのでそちらを紹介します。なお、リストから生徒のメールアドレス一覧を取得して、それを配列として格納していきます。メールアドレスの取得方法の詳しいやり方はClassroomに所属している生徒の一覧を取得する方法を参考にしてください。

let pageToken = "";
do {
  let studentList = Classroom.Courses.Students.list(courseId, {"pageToken": pageToken);
  let studentEmailList = [];// 空の配列を用意
  for (i = 0; i < studentList['students'].length; i++){
    let student = studentList['students'][i];
    studentEmailList.push(student['profile']['emailAddress']);//生徒のアドレスを配列に追加
  }
  pageToken = studentList.nextPageToken;//しおりを挟む。最後のページでなければまた「do」する
} while (pageToken);//最後のページまで行ったら処理を辞める

do{} while()メソッドは、whileがFalse(今回はpageToken=null)にならない限り、doを続けるというメソッドです。
nextPageTokenは次のデータがない(最後のページまで読み終えたら)、nullを返してくれるので、そうなったら処理を辞めてくれるんですね。
これで、上限30を超えてリストが取得できます!

以上、参考になれば嬉しいです。いや~~~しかし、今回も分からな過ぎて、pageTokenに関してのいろんな記事を読んだのですが、、、
なんでこうも初心者に分かりづらい、ないし、けっこう間違っている記事が多いのでしょうか。。。この辺の不親切さが、プログラミング学習に挫折する要因になっているような気がします。
Google Classroom APIは日本語の情報が少ないため、今後も様々トライしてみた結果を記事に書いていきたいと思います!