Notion による Google Form のリアルタイム集計 : Notion 解説(39)

はじめに

Notion が Mermaid.js の描画に対応しました。グラフが Codeblock で書けるようになりました。要望があったので、Google Form をリアルタイムで集計する Notion ページを作ってみることにしました。いつものように作りながら記事を仕上げていきます。

Google Form の作成

とりあえず適当にフォームを作ってみました。内容は適当です。

f:id:hkob:20211224092626p:plain
適当に作ったフォーム

何はなくともスプレッドシートを作成します。

f:id:hkob:20211224092752p:plain
スプレットシートの作成

新しいスプレッドシートを作成します。

f:id:hkob:20211224092832p:plain
新しいスプレッドシートを作る

シートが作成されました。まだ何も入れていないので空です。テスト用なので名前などの個人情報は集めていません。データがないとテストできないので、フォームに幾つかのデータを入れておきましょう。

f:id:hkob:20211224092938p:plain
作成されたスプレッドシート

こんな感じでダミーデータを入れてみました。

f:id:hkob:20211224093318p:plain
ダミーデータ挿入

Google Apps Script の作成 (集計部分のみ)

Google Apps Script を作成します。以前と異なり、拡張機能のところに移動していました。

f:id:hkob:20211224093402p:plain
Google Apps Script

ひとまずテストのために値が取得できるかだけ確認してみます。こんなコードを書きました。B2 からB列の一番下までのデータを値で取得してきます。

// 現在のアクティブシートを得る
function getSheet() {
  return SpreadsheetApp.getActiveSheet()
}

function calcStats() {
  const sheet = getSheet()
  const values = sheet.getRange("B2:B" + sheet.getLastRow()).getValues()
  console.log(values)
}

保存するとコードの上の部分がこんな感じに変わります。デバッグの右側を「calcStats」に変更して「実行」をクリックします。

f:id:hkob:20211224094937p:plain
実行ボタンなど

個人情報をアクセスするので権限の確認が入ります。

f:id:hkob:20211224094226p:plain
権限を確認

アプリの素性がわからないので、警告が出てきます。自分で作ったものなので「詳細」をクリックします。名前をつけているはずなのに「無題のプロジェクト」になってしまっていますが、気にしないことにします。

f:id:hkob:20211224095343p:plain
アカウント確認

進んだ先のページで「許可」をクリックします。

f:id:hkob:20211224094704p:plain
プロジェクトを信頼

実行結果が表示されます。先ほどのダミーデータが取得できました。結果は配列の配列として入っていることがわかります。後はコードを書くだけです。

f:id:hkob:20211224095539p:plain
実行結果

集計するところまで書いてみました。updateCodeBlock で stats を取得して、表示してみました。

// 選択肢
const selection = [
  "自分でプログラムコードを書いている",
  "Automate.io や Zapier を使っている",
  "Notion しか使っていない",
  "Notion もまだ使っていない"
]

function outsideSelection(value) {
  return selection.indexOf(value) == -1
}

function calcStats() {
  const sheet = getSheet()
  const values = sheet.getRange("B2:B" + sheet.getLastRow()).getValues()
  const stats = values.reduce((result, line) => {
    str = line[0]
    if (str in result) {
      result[str] += 1
    } else {
      result[str] = 1
    }
    return result
  }, {})
  let other = Object.keys(stats).filter(outsideSelection).map(k => stats[k]).reduce((s, v) => s + v, 0)
  stats["その他"] = other
  return stats
}

function updateCodeBlock() {
  const stats = calcStats()
  console.log(stats)
}

その他の意見は「その他」として集計されています。

f:id:hkob:20211224104431p:plain
実行結果

Notion API 部分は Notion のサンプルページを作ってから取り組みます。

Notion ページの作成

Codeblock を一つだけ作ってみました。言語を Mermaid にし、プレビュー状態にしておきました。

f:id:hkob:20211224105329p:plain
codeblock を一つだけ作成

共有で API test のインテグレーションを招待しています。今回は書き換えをしたいので「編集権限」にしておきます。

f:id:hkob:20211224105527p:plain
インテグレーションの招待

次に作成したコードブロックのリンクをコピーします。ブロックの id が必要なためです。適当なテキストエディタにコピーしておきます。

f:id:hkob:20211224105637p:plain
コードブロックのリンクを取得

これで Notion の作業は終了です。

Google Apps Script の作成 (Notion API 部分)

Notion 側の準備ができたので、Notion に送る部分を作成します。まず、インテグレーションのキーと先ほどのブロック ID を Script のプロパティに登録してしまいます。登録専用の関数をいつものように使います。まずこの状態でそのまま貼り付けて storeTokenAndId() を実行してみます。

// MY_NOTION_TOKEN と DATABASE_ID をプロパティに登録する(1回だけ使い、終わったらIDを消す)
function storeTokenAndId() {
  const scriptProperties = PropertiesService.getScriptProperties()
 scriptProperties.setProperties({
    "MY_NOTION_TOKEN": "ここに「Notion Token」を記述",
    "PAGE_ID": "ここに「ページID」を記述",
    "BLOCK_ID": "ここに「ブロックID」を記述"
  })
  // 登録できたことを確認
  console.log("myNotionToken = " + myNotionToken())
  console.log("blockId = " + blockId())
}

// MY_NOTION_TOKEN を取得
function myNotionToken() {
  return PropertiesService.getScriptProperties().getProperty("MY_NOTION_TOKEN")
}

// PAGE_ID を取得
function pageId() {
  return PropertiesService.getScriptProperties().getProperty("PAGE_ID")
}

// BLOCK_ID を取得
function blockId() {
  return PropertiesService.getScriptProperties().getProperty("BLOCK_ID")
}

実行するとこんな感じになります。

f:id:hkob:20211224111538p:plain
プロパティ登録の動作確認

動いていることが確認できたら、インテグレーションのトークンとブロックIDを書き換えて再度実行します。インテグレーショントークンは Notion の設定のインテグレーションで「トークンをコピーする」から得られます。トークンを作っていない人は、「独自のインテグレーションを開発する」の部分から作ってください(ここは省略します)。

f:id:hkob:20211224110444p:plain
インテグレーショントークンの取得
また、ページID は先ほどテキストエディタにコピーしたリンクの「#」より前の16進数部分です(/や-より後ろの部分)です。さらに、ブロックIDは「#」から後ろの部分です。これに3つの値をコピーしたら、再度 storeTokenAndId を実行します。

成功したら、storeTokenAndId 関数は消してしまってください。コードに危険な文字列などを残さないためにプロパティに格納しているので、この関数はもう必要ありません。

次に mermaid のデータ文字列を作成します。今回は pai チャートを表示します。updateCodeBlock から mermaidCode を呼び出すように変更して表示してみます。

function mermaidCode(stats) {
  ans = selection.reduce((result, k) => {
    return result + '  "' + k + '" : ' + stats[k] + "\n"
  }, "pie title Notion API アンケート\n")
  ans = ans + '  "その他" : ' + stats["その他"]
  return ans
}

function updateCodeBlock() {
  const stats = calcStats()
  const code = mermaidCode(stats)
  console.log(code)
}

f:id:hkob:20211224113104p:plain
作成した mermaid コード

同様に API 用の payload を作ります。

function updatePayload(code) {
  return {
    "code": {
      "text": [
        {
          "text": {
            "content": code
          }
        }
      ],
      "language": "mermaid"
    }
  }
}

function updateCodeBlock() {
  const stats = calcStats()
  const code = mermaidCode(stats)
  const payload = updatePayload(code)
  console.log(payload)
}

ここの出力画面を撮り忘れましたが、ちゃんと動いていました。payload できてしまえば、いつものルーチンのものを持ってきます。updateCodeBlock も完成させてしまいましょう。

function sendNotion(url, payload, method){
  let options = {
    "method" : method,
    "headers": {
      "Content-type": "application/json",
      "Authorization": "Bearer " + myNotionToken(),
      "Notion-Version": "2021-08-16",
    },
    "payload" : JSON.stringify(payload)
  };
  // デバッグ時にはコメントを外す
  //Logger.log(options)
  return JSON.parse(UrlFetchApp.fetch(url, options))
}

function updateBlock(blockId, payload) {
  let url = "https://api.notion.com/v1/blocks/" + blockId // API URL
  sendNotion(url, payload, "PATCH")
}

function updateCodeBlock() {
  const stats = calcStats()
  const code = mermaidCode(stats)
  const payload = updatePayload(code)
  updateBlock(blockId(), payload)
  Utilities.sleep(1000);
  // もし、その他の意見をページに追加するようなら以下に記載
  // 最終行がその他の意見だったら pageID で箇条書きを追加するなどをすればよいかと。
}

とりあえずチャートを更新する部分まで完成したので、実行してみます。ここで、外部サービスのアクセスがあったので、再度確認が出てきます。こちらも許可とします。

f:id:hkob:20211224114539p:plain
外部サービスへの接続許可

実行したらこうなりました。

f:id:hkob:20211224115508p:plain
更新されたグラフ

完成したので「デプロイ」しておきます。右上のデプロイを実行します。

f:id:hkob:20211224115728p:plain
新しいデプロイ

とりあえず update pie chart くらいにしておきます。

f:id:hkob:20211224115857p:plain
デプロイの詳細

Google Form との連携

次にトリガーを設定します。開いたら右下の「トリガーを追加」をクリックします。

f:id:hkob:20211224120005p:plain
トリガ設定

設定画面は以下の通りです。関数は updateCodeBlock、バージョンは先ほどデプロイした最新版にします。ソースはスプレッドシートで、イベントはフォーム送信時になります。これで、フォーム送信時にトリガーをかけることができます。

f:id:hkob:20211224120123p:plain
トリガの詳細設定

設定すると再度認証が入りますので、許可します。設定するとこんな感じになります。

f:id:hkob:20211224120402p:plain
トリガ一覧

せっかくなので Notion にフォームを埋め込んでみました。実際に送信してみるとちゃんとパイチャートが変化するのがわかります。うまくいきましたね。

f:id:hkob:20211224120553p:plain
フォームを埋め込み

おわりに

作成したページはここです。せっかくなのでアンケートに答えてみてください。もし Form 連携の参考になれば幸いです。

hkob.notion.site


hkob.notion.site