DataverseのWebAPIで5,000件より多いデータを取得する

#概要
Dynamics 365やPower Apps モデル駆動型アプリのデータベースはDataverse（旧Common Data Service）というものになっています。
これに対してWebAPIを実行すると簡単にデータを取得できるのですが、データ取得は5,000件までという制限があります。
Power Automateを使用する場合も含めて全件取得する方法を記載します。


#DataverseへのWebAPI
まずはWebAPIについて説明します。これを使った仕組みであるPower Automateについても記載します。

##WebAPI実行
MSのDocsに例も含めて記載されています。
URLは詳細設定 > カスタマイズ > 開発者リソースからも確認できますが異なるURLが記載されています。どちらでも使用はできるようです。
WEBブラウザーのURLに入力してみると簡単に試せます。

https://docs.microsoft.com/ja-jp/powerapps/developer/data-platform/webapi/query-data-web-api#limits-on-number-of-entities-returned

以下のような例が書いてありますが、「accounts」はデータ取得対象エンティティのスキーマ名です。複数形で入力します。
カスタムエンティティでもsをつけるなど複数形にする必要があります。

```
GET [Organization URI]/api/data/v9.1/accounts
```

##Power Automate
以下のコネクターを使ってデータを取得できます。
Dynamics 365・Power Apps モデル駆動型アプリのデータもこれで取得できます。
名前は2021年3月時点でCommon Data Serviceとなっていますが、そのうちDataverseに変わるものと思われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/69c48c58-7182-c331-5232-4345b4c53274.png)

データを取得するアクションは「行を一覧にする」です。（翻訳の関係かわかりにくいため、そのうち名称が変わるかもしれません。）
以下のようにいろいろなプロパティが表示されますが、？を押して詳細情報を押すと説明が記載されたWEBページへジャンプします。英語ですが。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/7dc6decc-6348-70ed-baa8-f79c3084fe6a.png)

詳細情報を開くと表示されるページ。こちらは英語なのでPower Automateの項目と紐づきにくいものもありますが
Power Automateの表示順と同じ順番で並んでいるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/f6f9a66e-31cb-3291-ace9-6679d4536589.png)
https://docs.microsoft.com/ja-jp/connectors/commondataserviceforapps/#list-rows

上記をみたら分かるのですがPower Automateで指定するパラメーターはWebAPIで指定するパラメーターと同じものなので、
Power AutomateのUIでみたまま思ったことができる、というわけにはいかないようです。
記述の形式などの知識が必要です。

##5,000件制限
上記にも上げたページに以下のような記載があります。
１要求ごとに5,000件で、@odata.nextLinkを使えばその続きも取得できるとのことです。

>小さなページ サイズを指定しない限り、各リクエストに対して最大 5000 のエンティティが返されます。 クエリ フィルターの条件と一致するエンティティがさらに存在する場合、@odata.nextLink プロパティが結果と共に返されます。 @odata.nextLink プロパティの値を新しい GET 要求と共に使用して、次のページのデータを返します。

https://docs.microsoft.com/ja-jp/powerapps/developer/data-platform/webapi/query-data-web-api#limits-on-number-of-entities-returned

5,000件以上あるエンティティに対してデータ取得を実行した場合がこちら
"@odata.nextLink"が設定されて返ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/3eb5d0f5-5ea1-40b1-f535-fc25e00395c6.png)

Power Automateの場合は、「次のリンク」という動的なコンテンツにこの値が代入されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/ab41c133-9600-435b-de32-f84e2433c499.png)

#Power Automateで5,001件以降を取得する
##Power Automateでは「次のリンク」をそのまま使えない
この「次のリンク」をアクション「行を一覧で取得する」の「トークンをスキップする」にそのまま入れられれば便利なのですが
ここには$skiptokenに設定するパラメータ部分だけを指定する必要があるため
そのまま入れるとエラーになってしまいます。


##データを取得するフローを構築する
以下は5,000件を超えるデータに対して「行を一覧にする」を実行したい場合に、5,001件以降のデータも取得するようにしたフローです。
変数にskiptokenというのを作成して、これが「end」になるまでDo untilしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/88397f03-bc49-7ba2-3592-1fb03a839c40.png)


###初回のskiptoken
「トークンをスキップする」にnullを入れるとエラーになってしまいます。
初回は以下を指定します。

```
<cookie pagenumber='1' />
```

###skiptokenを取得するためのアクション
実行結果が5,000件以下の場合は"@odata.nextLink"が設定されないため、
これを条件にnullの場合は変数skiptokenに"end"という文字列を代入します。
これをループの終了条件にします。

nextLinkが返されている場合は以下を変数skiptokenに代入します
$skiptokenのパラメータ部分をsubstringで切り取っています。
切り取る範囲に固定値が入っているのは、行を一覧にするでの実行内容が変わらなければ文字数が一定のようだからです。
エクセルのFind関数みたいなのがあればもっときれいに行くのでしょうが、もし方法を知っている方がいらっしゃれば教えてください。
デコードした値を変数に代入します。

```
decodeUriComponent(substring(outputs('行を一覧にする')?['body/@odata.nextLink'], 88, 316))
```

上記は以下のようなnextLinkが返ってきているときの例です。

```
"@odata.nextLink":"https://**********.crm7.dynamics.com/api/data/v9.1/contacts?$select=fullname&$skiptoken=%3Ccookie%20pagenumber=%222%22%20pagingcookie=%22%253ccookie%2520page%253d%25221%2522%253e%253ccontactid%2520last%253d%2522%257b02B020EA-D683-EB11-B1AB-000D3A6FA218%257d%2522%2520first%253d%2522%257b65FCC3C6-D683-EB11-B1AB-000D3A6FA218%257d%2522%2520%252f%253e%253c%252fcookie%253e%22%20istracking=%22False%22%20/%3E"}}
```

Power Automateでは詳細設定 > カスタマイズから確認できるURLではなくてDocsに書かれている方が使われています。
```
GET [Organization URI]/api/data/v9.1/accounts
```

###Do untilのループ回数、実行時間
初期値が60なのでほとんど気にすることはないと思われますが、その回数までしかループしません。
60だと設定が失敗しているときに実行がなかなか終了しないため、2や3という小さい数値でテストするほうが楽です。
処理に時間がかかることが想定される場合は実行時間も気にする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/04e1e689-89c0-1cfe-9ecf-c443058c9f8c.png)

###実行結果の確認
Dataverseへ要求URLを送信した結果は、実行結果からダウンロード可能です。
うまくいかない場合はここからnextLinkで返ってきている値などを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190486/daec0a0d-e2d2-b804-473e-9730cdf31a77.png)

###処理の実装
この例だとただデータを取ってきて何もしていないので、
データが取得できていることをテストしたのち、
「行を一覧にする」の後にFor eachのアクションなどを使って処理を行います。


#余談
Power Automateで式を更新したあとに、「更新」ボタンを押し忘れて変更前のままテストしていることがたまにあります。
直したはずなのに、、というときは本当に更新されているか確認したほうがいいです。