0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Entra ID ユーザーを“何百・何千” IN で検索

Posted at

$filter=id in (…) の壁を Chunk 分割+並列制御で突破する実践パターン

1. 背景 ― Entra ID (旧 Azure AD) で大量ユーザーをまとめて取得したい

  • 監査や移行時、指定されたユーザー ID 群 (Object ID) を一括で取得したい
    例)外部 CSV に 8 000 ID、これを Microsoft Graph で /users 検索
    ($filterを使用する際に、Advanced queryにする必要な場合がある。)
  • Graph の典型的な書き方は
    GET /v1.0/users?$filter=id in ('id-1','id-2',…)
    
    • しかし ID が多すぎると URL 長さ制限の壁 に当たる場合がある。
    (HTTP/1.1 ゲートウェイで ≒ 2 048 byte を越えると HTTP 414 URI Too Long)

要するに 「1 回で投げられる ID 数は数百が限界」。
単純ループ (8 000 回) では遅すぎるし、8 000 回を並列処理にするとGraph APIのアクセス制限がかかってくる。

つまり、太いクエリ×適度な並列 の設計が必要。

2. 攻略プラン

ステップ 目的
Chunk 分割 – 例:200 ID / Chunk URL 8 KB とクエリ制限に収める
並列上限を適切に固定 Entra ID テナントの同時リクエスト閾値を守る

3. TypeScript 実装スニペット

import axios, { AxiosRequestConfig } from 'axios';
import pLimit from 'p-limit';
import axiosRetry from 'axios-retry';

/* ① 429 / 5xx を自動再試行 */
axiosRetry(axios, {
  retries: 5,
  retryDelay: axiosRetry.exponentialDelay,
  retryCondition: err => {
    const s = err.response?.status;
    return s === 429 || s >= 500;
  },
});

/* ② パラメータ */
const CHUNK  = 200; // 200 ID / クエリ
const CONCUR = 4;   // 4 クエリ同時まで

export async function fetchUsersByIds(token: string, ids: string[]) {
  if (!ids.length) return [];

  /* Chunk 化 */
  const chunks: string[][] = [];
  for (let i = 0; i < ids.length; i += CHUNK) {
    chunks.push(ids.slice(i, i + CHUNK));
  }

  /* p-limit で並列数を固定 */
  const limit = pLimit(CONCUR);
  const tasks = chunks.map(batch =>
    limit(() => {
      const filter =
        `id in (${batch.map(id => `'${id}'`).join(',')})`;

      return fetchUsers(token, filter);   // ← 既存のページング付き取得関数
    }),
  );

  const pages = await Promise.all(tasks);
  return pages.flat(); // 重複 ID がなければこれで完了
}

/* 参考:1 クエリ分を取得 */
async function fetchUsers(token: string, filter: string) {
  const users: any[] = [];
  let next = 'https://graph.microsoft.com/v1.0/users';

  const cfg: AxiosRequestConfig = {
    headers: {
      Authorization: `Bearer ${token}`,
      ConsistencyLevel: 'eventual',   // 高度フィルタ必須
    },
    params: {
      $select: 'id,displayName',
      $filter: filter,
      $count : 'true',
    },
  };

  while (next) {
    const { data } = await axios.get(next, cfg);
    users.push(...data.value);
    next = data['@odata.nextLink'];
  }
  return users;
}

まとめ

  • 「太いクエリ×適度な並列」でURL長さ制限とAPIアクセス制限を回避つつ、高速にリクエストを実現
  • 同じような実装方法で、WEBクローラにも使えるだろう
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?