# Device Query

Device Query は、SQL ライクなクエリ言語を使ってデバイス全体のフリートを検索できる機能です。デバイスのメタデータ、接続状態、最新のシャドウ状態を一つのクエリ可能なインターフェースに統合しているため、複数のデータソースを自分で結合する必要がありません。

## Device Query を開く

Fleets のデプロイメントで、左メニューの **Device Query** をクリックします。

![device_query](./_assets/device_query.png)

## クエリの作成

テキストエディターにクエリを入力し、**Run Query** をクリックします。結果は下の **Query Results** テーブルに表示されます。

クエリ結果には、条件に合致した各 Thing の名前、MQTT クライアント ID、ステータス、タグが含まれます。

### 例の手順

この例では、オフラインのスマートロックをすべて検索します。

1. クエリエディターに以下を入力します。

   ```
   thingTypeName:com.demo.fleets.smart-lock AND status:offline
   ```

2. **Run Query** をクリックします。

   **Query Results** テーブルに、名前、MQTT クライアント ID、ステータス、タグを含む一致するすべての Thing が一覧表示されます。

3. Thing 名をクリックすると詳細ページが開き、最後のオフライン時間やシャドウ状態を確認できます。

![device_query_results](./_assets/device_query_results.png)

### クエリ構文

クエリは `field:value` の構文を使い、比較、否定、論理演算子、グルーピングをサポートします。

| パターン | 説明 | 例 |
|---|---|---|
| `field:value` | 完全一致 | `status:online` |
| `field:a,b` | 指定した値のいずれかに一致（IN） | `operationMode:cool,heat` |
| `field:*` | レポートされた状態にフィールドが存在する | `temperature:*` |
| `field:>value` | より大きい（数値フィールド） | `temperature:>25` |
| `field:>=value` | 以上 | `battery:>=20` |
| `field:<value` | より小さい | `humidity:<60` |
| `field:<=value` | 以下 | `voltage:<=3.3` |
| `NOT field:value` | 条件の否定 | `NOT status:offline` |
| `a AND b` | 両方の条件を満たす | `status:online AND temperature:>30` |
| `a OR b` | いずれかの条件を満たす | `status:online OR temperature:>40` |
| `(a OR b) AND c` | 優先順位を制御するグルーピング | `(mode:cool OR mode:heat) AND connected:true` |

`AND` と `OR` は明示的に記述する必要があります。演算子なしの `a:1 b:2` は無効です。

### クエリ可能なフィールド

| フィールド | 説明 |
|---|---|
| `thingName` | Thing 名 |
| `thingTypeName` | Thing タイプ名 |
| `status` | 接続状態：`online` または `offline` |
| `connected` | `status` のブール相当値：`true` はオンライン、`false` はオフライン |
| `hasDelta` / `shadow.hasDelta` | 望ましい状態と報告された状態が異なる場合は `true` |
| `shadow.version` / `shadowVersion` | 現在のシャドウのバージョン番号 |
| `lastConnectedAt` | 最終接続時刻（等価比較推奨） |
| `shadow.reported.<key>` | 最新の報告状態の任意のキー |
| `shadow.desired.<key>` | 最新の望ましい状態の任意のキー |

報告状態のフィールドでは、`shadow.reported.` のプレフィックスを省略してプロパティ名だけを使うことができます。`reported.<key>` も有効です。例えば、`temperature:>25`、`reported.temperature:>25`、`shadow.reported.temperature:>25` はすべて同じ意味です。

上記管理リストにないフィールド名はすべてシャドウの報告キーとして扱われます。

### クエリ例

オンラインのすべてのデバイスを検索：
```text
status:online
```

切断されたデバイスを検索：
```text
connected:false
```

望ましい状態が保留中のデバイス（デルタが存在）を検索：
```text
hasDelta:true
```

温度が30℃を超えるサーモスタットを検索：
```text
thingTypeName:Thermostat AND temperature:>30
```

バッテリー残量が少なく、なおかつオンラインのデバイスを検索：
```text
status:online AND battery:<20
```

複数のモードのいずれかにあるデバイスを検索：
```text
operationMode:cool,heat
```

少なくとも一度は報告されたフィールドを持つデバイスを検索：
```text
temperature:*
```

## フィルターの追加

**+ Add filter** をクリックして、クエリ文字列に加えて構造化フィルターを適用できます。利用可能なフィルター：

- **Things**：特定の Thing 名に結果を制限
- **Group**：特定の Thing グループのメンバーに結果を制限
- **Thing Type**：特定のタイプの Thing に結果を制限
- **Status**：`online` または `offline` でフィルター
- **Reported Time Window**：指定した時間範囲内に状態を報告した Thing に結果を制限

すべての有効なフィルターは `AND` で結合されます。

![device_query_add_filter](./_assets/device_query_add_filter.png)

## クエリ履歴

**Query History** をクリックすると、現在のセッションの過去のクエリを表示および再実行できます。

## 時系列フィルター

**Reported Time Window** フィルターは、指定した時間範囲内にシャドウ状態を報告した Thing に結果を制限します。最新のスナップショットだけでなく、GreptimeDB の履歴時系列データを参照します。

コンソールでは、**+ Add filter** から **Reported Time Window** フィルターを追加し、開始時刻と終了時刻を設定します。

REST API 利用時は、リクエストボディに以下のパラメータを渡します：

| パラメータ | 説明 |
|---|---|
| `tsFrom` | 時間範囲の開始（RFC3339 UTC）。`tsTo` とセットで必須。 |
| `tsTo` | 時間範囲の終了（RFC3339 UTC）。`tsFrom` とセットで必須。 |
| `tsFieldName` | 任意。指定したトップレベルキーをその時間範囲内に報告した Thing に限定。省略すると範囲内の任意の報告行にマッチ。 |
| `tsLimit` | 時系列の事前フィルターで候補となる最大 Thing 数。デフォルトは `1000`、最大は `10000`。ページネーションの `limit` とは異なります。 |

例：1時間の時間範囲内に温度を報告したオンラインデバイスを検索：
```json
{
  "query": "status:online",
  "tsFrom": "2026-05-27T00:00:00Z",
  "tsTo": "2026-05-27T01:00:00Z",
  "tsFieldName": "temperature",
  "page": 1,
  "limit": 20
}
```

::: warning 重要なお知らせ

時系列フィルターは GreptimeDB を参照します。GreptimeDB が利用できない場合、`tsFrom`/`tsTo` を使ったクエリは `503 Service Unavailable` を返します。

:::

## REST API

Device Query は REST API でも利用可能です：

```text
POST /api/v1/device-query/search
```

デプロイメントの API エンドポイントをベース URL として使用し、デプロイメント API キーを使った Basic Auth で認証してください。エンドポイントの取得方法やキーの作成方法は [Deployment API Keys](./deployment/emqx_fleets_manage_deployment.md#deployment-api-keys) を参照してください。

## 次のステップ

- [Device Shadow](./device_shadow.md)
- [Thing Groups](./device_management/thing_groups.md)
- [Commands and Jobs](./commands_and_jobs/commands_and_jobs_overview.md)
