Power AutomateからSharePointリストの複数行をループを使わずに更新する方法

一般的なデータベースのSQLでは、なんらかの条件にマッチする行をまとめて更新することができます。

例えば以下のような表を用意したときに、SQLならば以下のように記述するでしょう。

UPDATE testList
SET    "boolB" = FALSE
WHERE  "textA" = 'Bye';

残念ながら、SPOリストではSQLのように条件にマッチする行の指定の項目を一括で更新することができません。

一般的にSPOリストではApply to eachを使う?

おそらく一般的にはこのようにすると思います。

フィルタクエリにODataクエリの記述で

textA eq 'Bye'

と書くことで、Byeにマッチする行だけを取得し、「項目の更新」アクションを使ってそのIDに対して更新を繰り返します。

つまり、「項目の更新」アクションは、更新が必要な行数のぶんだけ呼び出されます。処理はシンプルですが問題は「Apply to each」がPower Automateのクラウドフローでは非常に遅いことです。数行の更新であればこれで問題ありませんが、数百行をまとめて更新するような場合には途方もない時間が必要になります。

してみる

Aplly to eachでどのくらい時間がかかるか確認してみる

SPOリストにテスト用の50行のBye項目を作成してみます。

更新処理を動かしてみると、50行を更新するのに31秒かかりました。

一括で更新するには?

クラウドフローを高速に実行するには、Apply to eachを極力使わずに他の手段で代替するのは定石です。

SharePointで既存のアクションがないような操作を実行するには、「SharePointにHTTP要求を送信します」アクションを使います。このアクションは、SharePointのREST APIを利用できます。レガシーとかSharePoint REST API v1とかいうように呼ばれている仕組みを使うことができます。

アクションはこんな感じになっていて、URIに操作に対応したAPIのエンドポイントを記述し、APIに対してボディに実行したい内容を記述して送信することで操作が可能になります。今回のような複数のSPOリストの行をまとめて更新するという場合には、ボディにその内容を記述してやるのですが・・・・。

仕様を調べた(こちら飛ばしてもらっても大丈夫です)

これが一筋縄では行きませんでした。

$batch方式

まず、Microsoftの公式Learnにて。

https://learn.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-lists-and-list-items-with-rest#update-list-item

レST A日を使った項目の更新のサンプルとしてこのような記述がありました。

POST https://{site_url}/_api/web/lists/GetByTitle('Test')/items({item_id})
Authorization: "Bearer " + accessToken
Accept: "application/json;odata=verbose"
Content-Type: "application/json"
Content-Length: {length of request body as integer}
If-Match: "{etag or *}"
X-HTTP-Method: "MERGE"
X-RequestDigest: "{form_digest_value}"

{
  "__metadata": {
    "type": "SP.Data.TestListItem"
  },
  "Title": "TestUpdated"
}

__metadata という項目で情報を渡すと更新してくれるようです。 GetByTitleのカッコにはSPOリストの名前が。items()のカッコのなかには変更する行のIDが入ります。typeの値SP.Data.TestListItemの「Test」の部分が、なんとテーブル名ですのでここも書き換えるのを忘れると詰みますな。

この方法だと結局1行しか更新ができません。

そこで、ネットを探しあるいたところこちらのサイトを見つけました。

https://www.codesharepoint.com/sharepoint-tutorial/batch-crud-operation-using-sharepoint-rest-api

HTTPリクエストではSQLのようにかんたんな指示で複数行をまとめて指定できるわけではなく、指定したID(行)の変更指示をまとめてボディに記述して一括で実行を投げるバッチ処理のような仕組みになっていることがわかりました。

下の表記は更新ではなくて行追加のバッチ処理なのですが、複数のチェンジセットをを「–」から始まる区切り線のようなもので与えて、それをバッチスタートとバッチエンドの目印で大きく囲んで与えるのですね。マジかよ!?

上記のサイトではJavaScriptでこの文字列を作成していますので、これをPower Automateのクラウドフローに移植すれば実現するはず?

こんな感じです。これテスト時にはうまくいったのですが、テナント変えたら何故かうまく行かず。記述する内容もすごく複雑なのでもっとかんたん似できないかしら

BulkValidateUpdateListItems方式

他に方法がないのかさがしまくったところ、こちらの記事を見つけました。

https://michalkornet.com/2024/04/22/SharePointApi-BulkValidateUpdateListItems.html

サンプルを見てわかるとおり、SPOリストの行IDを配列で与えてやるだけでまとめて更新ができるっぽいです。これはすごく使いやすい!!

興味深いのは、MicrosoftのLearnで使い方について公式のリファレンスを探してみても見つからず。あったのはコチラだけ。

https://learn.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-csomspt/ebc47581-36e4-457b-8045-a4cf1f4da501

どうやらCSOM由来の非公開エンドポイントっぽいのです。

やってみた! フローはQiitaで!

どんなふうにBodyを構成したらよいのか、思考覚悟が正直なところむちゃくちゃ大変でした。

結果的にとんでもないエンドポイントの情報をみつけて紹介することができたのは良かったです。

BulkValidateUpdateListItems の情報はググっても出てこず。もしかして日本語記事としては初なのでは?とやや興奮気味。

できる限りシンプルに。コピペで他のリストにも対応しやすいように紹介したので、ぜひご覧ください。

https://qiita.com/DaddyDaddy/items/87dab3c6eed3d07193dc

Qiitaでこんな記事も書いてます!