• Reading time:9 mins read

お仕事データをすべてNotionに集約しよう、という謎の追い込みを懲りずに続けている私(@saosaoyamayama)です。

本来できるはずの「Notionにスプレッドシートを埋め込んでNotion上で編集」がなぜかできず、Notionのサポセンに相談しています。

さて今回はNotionのデータベースをスプレッドシートに自動で転記しますよ〜。Google Apps Script(GAS)の出番です。

ほとんど先人の知恵を丸パクリしているので、コードではなくうまくいかなかったことや気付いたことなどを添えておこうと思います。

※なお私はGASを使う経験自体は結構ありますが、ノンプログラマーかつ先人の知恵を拝借して部分的にコードを変えて使うレベルのビギナーです。ビギナーでも使えますよってことはお伝えしておきます。

参考にしたサイト

本当に何から何までありがとうございます。

基本的なコードはこちらのサイトさまを見ていただいたほうがいいと思います。私が頭を悩ませて書いたコードではありません。

スプレッドシートのデータをNotionに移すっていうのもやりまして、こちらもうまくいきました。「最終的にはうまくいった」ってだけでいろいろ試行錯誤したんですよね。

スプシのデータ→Notionについては結構情報があるけれど、Notionのデータベース→スプシについては情報がちょっと少ない印象でした。

あっても「コードかいつまみ型」の解説サイトが結構多くて、初心者にはワケわかんないっす。

qiitaは「おはようからおやすみまで」書いてくださる記事が多くて助かります。上記サイトは本当に参考になりました。

Notionのデータベースをスプシに出力する時に大変だったこと

適当に感覚でコードをいじったら全然うまくいかなかったので、qiitaとまったく同じデータを作って動かして、動くことが確認できてからコードを書き換えていきました。

その過程で手が止まったこと・めっちゃ苦労したことを4つ挙げておきます。

  • GASでフィルターをかけるときのカッコとカンマが合わない(能力の問題)
  • 「開始日」だけの取得ができない(実際はできますよ)
  • マルチセレクトタグが1つしか出力できない(複数出力できますよ)
  • タイトルが入っているのにタイトルが出力されないデータがある

4つ目はほんと、苦労した。

GASでフィルターをかけるときのカッコとカンマが合わない

コードのレイアウトを変えて理解しやすくする
私は右のように書き換えたほうが飲み込める

何の話だよって感じですね。

目が慣れていないというか、カンマがあったりなかったり、カッコが角括弧だったり波括弧だったり括弧だったりするのでペア迷子だし、カンマつけるんだっけ、どの括弧の後だっけ、と大混乱。

ステータスは2つのどちらか(or)、ライター名は3つのどれか(or)に一致するモノを必須(and)としてデータを引っ張ってきてね、ってことなんです。

頭弱い私にもわかるように並べ替えたのが、キャプチャの右側ですね。んははは、我ながらひどい

ただ、GASはコードを書いて保存するとき、あるいはスクリプトを動かすときに「あんたオカシイで」って教えてくれるから親切ですね。どこがおかしいか、も書いてくれるし。

まあ「どこがおかしいか」の部分は大抵隠れていて読めないんですけどね。

「開始日」だけの取得ができない

for (let item of tables.results) {
    while (tables.responses)
      i++;

    name = item.properties['記事タイトル'].title[0].plain_text;
    writer = item.properties['ライター'].select.name;
    status1 = item.properties['ステータス'].select.name;
    content = item.properties['記事'].select.name;
    indate = item.properties['納品日'].date;

    array.push(
      [
        name
        , writer
        , status1
        , content
        , indate
      ]
    )
  }

赤字にした「date」です。結論、日付のデータは取得できているので、データをスプシに出力するという目的は果たせています。私の基礎知識が足りないだけです。

Notionで日付データを入力する場合、日付としては「開始日・終了日」が指定できて、それぞれの時間まで指定できます。

私が「納品日」として入力しているのは、Notionの日付データのうち「開始日」に当たる部分です。なので開始日だけを引っ張りたかったんです。

GASのログをコピーして確認したところ……。

Log
Log

開始日だけでなく、終了日もタイムゾーンもnull扱いで取得しています。で、スプレッドシートにもご丁寧にこのまま出力してくれるんですわ。

{start=2023-03-07, time_zone=null, end=null}

仕方ないのでスプシの関数で切り刻み、日付だけを取得しています。

=split("{start=2023-03-07, time_zone=null, end=null}","start=",false)
→{
→2023-03-07, time_zone=null, end=null}

=substitute(left("2023-03-07, time_zone=null, end=null}",10),"-","/")
=2023/03/07

GASで取得した日付データを「start=」で分割すると、2つめのデータは必ず開始日10桁から始まります。

2つめのデータの左から10文字だけを「left」関数で切り出して、「substitute」関数でハイフンをスラッシュに置換すれば、お望み通りの開始日ができあがり。

マルチセレクトタグが1つしか出力できない

もともと「記事」プロパティはマルチセレクト指定でした。

GASで取得してみると、マルチセレクトタグが3つ入っていても4つ入っていても、取得できたタグは1つのみ。

知識浅子は「そういう仕様なのか」と謎の理解を示し、セレクトプロパティを追加して記事種とそれ以外に分けたのでした。

結論、マルチセレクトのタグは全部取得できるっぽいことを知りました。美容院でブリーチしながら「うわ、できるっぽいぞ」と知りました。解説浅子ですね。

タイトルが入っているのに出力されないデータがある

これは情報がどこにもなくて、結構右往左往しました。

Notionの出力データ
E列が歯抜けになって苦労した

オレンジ枠内はGASで出力したNotionのデータです。なぜかタイトルが出力されないデータが2つあったんですよね。

キャプチャだとE列、ここがなぜか飛び飛びになっている。でもNotionのデータを確認するとタイトルがしっかりと入力してある。なぜだ……。結構煮詰まってしまってですね。

私の目に見えているNotionのタイトルは、幻覚なのでは?

そう思ってタイトルをコピーして、コードブロックに貼り付けてみたんです。当然幻ではなくて、きちんとテキストとしてペーストできました。

いやいや、そうじゃなくて。

貼り付けたタイトル、なんか黒々してないか? 太字になっているのでは?

もう1つのタイトルも同じように確認したところ、タイトルにBOLDが適用されていました。それ以外のタイトルはすべて平字です。

そこで2つのタイトルを平字に修正してGASを走らせたところ……。タイトル出力成功〜!

というわけで、データのタイトルにうっかり太字指定が紛れ込んでいると、GAS出力がうまくいかない可能性があるので、ぜひ覚えて帰ってください。

NotionDB→スプシに出力後どう使っているのか

Notionの出力データ
B列はクライアント側のステータス

先ほどと同じキャプチャです。

このスプレッドシートは私が作業用に作ったもので、これ以外にクライアントが管理するスプシ(記事種別タブに分かれている)があります。

MY作業シート上で①Notionデータ②クライアントデータを突き合わせて、クライアントデータで「公開済」になった記事がひと目でわかるようにするのが今回の作業の目的です。

Notionのデータを全部出力すると膨大なので、Notion側の作業ステータスが「執筆中・検収中」のものに絞って出力しています。

そうすると15件前後に収まるので扱いやすいなと。その15件のタイトルを、クライアントデータのタイトルと突き合わせて「クライアント側のステータス」を取得しています。

規則性がないデータを使いやすく加工できるのはスプシならでは

クライアントのスプシは行数4桁超えなのに規則性が弱く、「条件を絞ってデータを抽出する」のが困難です。

  • 関数を使っておらず皆が手動でソートし放題で並び順が変わる
  • 入力内容の自由度が高すぎて規則性に欠ける(日付欄に日付があったりなかったり)
  • 連番は振っていない
  • 勝手に連番振ったり関数入れたりできない

そのためMY作業シートにimportrangeで読み込んで、規則性を持たせたりフラグ付けたり切ったり貼ったりして扱いやすくしています。

たとえばタイトル。「現在のタイトル-改行-改行-新タイトル」だったり「タイトル-改行メ-モ書き」「タイトル(記事種)-改行-関連するURL」だったりするので、1行目のタイトルだけ残して他は消す。タイトルの後ろに括弧書きがあったら消す。

私のNotionには必ず1行目のタイトルを記載する。ただし管理の都合上、タイトルの頭に日付や数字を足しています。これはMY作業シート上に出力した後、関数・正規表現を使って消滅させています。

文字列の加工しやすさ、についてはまだまだスプレッドシートに軍配ですね〜。

クライアントデータは常時更新・Notionデータは時限式更新

取得したNotionのデータは関数を使ってクライアントデータと照合します。

クライアント側のデータは記事種ごとにタブが分かれているので、どちらのタブを使うか決めるところからスタートです。

  1. Notionの記事種を見て使用するタブを判定(if関数)
  2. NotionのタイトルとクライアントDBのタイトル照合
  3. タイトルが一致したら、クライアントデータの「ステータス」を取得(vlookup
  4. 「公開済」の場合は黄色にする

※vlookupを下から検証できることを知ったって話は最後に

クライアントデータが更新されればMY作業シート側も更新されるので、「タイムラグなし」でデータ照合したければNotionを使わずスプシ上で作業を完結するのがイチバンです。

でも私はそこまでのリアタイを求めないので、稼働時間内1時間に1回程度、MY作業スプシにNotionを出力するようにセット済です。つまりオレンジ枠のデータは1時間に1回しか更新しないってこと。

更新頻度はともかくとして、スプシを開かないと「公開済」が確認できないわけで……。ここはNotionの埋め込みブロックで対処。

スプシのプレビューをNotionに埋め込みトグル開閉で更新

トグルに埋め込みブロックを格納
トグルに埋め込みブロックを格納

上のキャプチャが埋め込みプレビューです。トグルに収納している、というのが結構ポイントだったりします。

まず、なぜプレビューの埋め込みなのか。編集じゃないのか。っていうのは私が聞きたいよ💢(Notionエンジニアさん調査中)

私のNotionはプレビューしか埋め込めないのです。まあ、うっかり編集しちゃうなんてこともなくて安心。

ただ、参照元のデータがいくらリアルタイムで更新されても、Notionのプレビューは更新されません。Notionの「再読み込み」するしかないか〜と思っていたところ……。

トグルの開閉操作で更新できることがわかりました。ステータスを確認したら閉じておいて、時々開いてステータスを確認しています。

なお「プレビュー」しか埋め込めないので「スクリプト発動ボタン」をスプシに設置しても押せません。そこがちょいと不便です。どうしても手動でスクリプトを動かしたいときは、トグル下のリンクからスクリプトを開いて動かします……。

【参考】vlookupを下から検証できると知った

クライアントデータの中では同一タイトルが何度も出てきます。で、シートの上部から順にデータを追加しているので、下に行くほど私が「今」使いたいデータが登録されているんですね。

vlookupは通常データベースの上部から検証していくので、同一タイトルが上部にあるとそれを優先的に「一致」とみなしてしまうので、正しいステータスが取得できません。

ライター名も含めれば? と思うかもしれませんが、タイトルもライター名も同じってことが結構あります。

そこで知ったのが「sort」と「row」の組み合わせです。

vlookup("hoge",sort('シート'!$A$2:$B,ROW('シート'!$A$2:$B),),2,false)

行(row)を降順(,)に並べ替えて(sort)使いますよってこと。降順の指定は本来「false」ですが、省略できるんだそうです。

以前vlookupを右から左に動かすっていうのを知ってものすごく感動して、未だにお世話になっていますが、下から上に検証って……これ知ってたらもっと私は……もっと私は……。

スプレッドシートのデータをNotionに格納するのもやっています

逆バージョンですね。GASを使ってスプシのデータをNotionに格納するっていうのももちろんやりました。

実作業では使わないことにしましたが、そのうち記事にしようと思います。

S.Nakayama

一帖半執筆工房代表。 デジタルマーケ企業のフリーランスPMとして計9サイトのコンテンツ制作を並行指揮した経験を持つ。 現在は企業の人材育成コンサルやメディア進行管理をしながら、グラフィックデザイン・文章校閲・校正者・ライターとしても活動中。 DigitalCameraWorld認定フォトグラファー、臨床検査技師。