# 实时数据库(WebSocket)

该功能可实现订阅数据表的数据增删改变化，当表数据改变时，客户端可以实时接收到数据的变化。

> **danger** 该操作适用于 SDK version >= 1.0.0-alpha-3

## 操作步骤

> **info** 使用实时数据库功能前需要先进行[登录操作](https://ifanr.gitbook.io/baas-js-sdk/flutter-sdk/schema/pages/AUxH1nSf6sZycuCZncXN#登录)

1.通过 `tableName` 实例化一个 `TableObject` 对象，操作该对象即相当于操作对应的数据表，这里推荐用 tableName

```dart
TableObject tableObject = new TableObject(tableName);
```

**参数说明**

| 名称        | 类型     | 必填 | 说明   |
| --------- | ------ | -- | ---- |
| tableName | String | 是  | 数据表名 |

> **info** 实时数据库功能无法订阅内置数据表，如 \_userprofile 表、\_richtextcontent 表等

2.发起数据表订阅操作

`var myEvent = tableObject.subscribe(event, where, onInit, onEvent, onError);`

**参数说明**

| 名称      | 类型       | 必填 | 说明                                  |
| ------- | -------- | -- | ----------------------------------- |
| event   | String   | 是  | 表数据变化的类型，有三种：create、update 和 delete |
| where   | Where    | 否  | 查询条件                                |
| onInit  | Function | 否  | 订阅成功回调                              |
| onEvent | Function | 否  | 订阅数据变化回调                            |
| onError | Function | 否  | 订阅动作出错回调                            |

> **info**
>
> * `create`、`update` 和 `delete` 三种数据变化类型需要分别订阅
> * `onInit` 回调函数将在订阅动作初始化成功时调用，一次 subscribe 订阅动作会触发一次
> * `onEvent` 回调函数将在数据表每次有相应动作变化时调用，参数是数据表变化了的数据项，三种事件类型对应得到的回调参数对象结构见下表
> * `onError` 回调函数将在订阅动作出错是调用，参数是错误信息

**onevent 回调函数参数说明**

`create` 事件得到的 `WampCallback` 类型：

| 名称           | 类型     | 说明                   |
| ------------ | ------ | -------------------- |
| event        | String | 事件类型，返回 "on\_create" |
| schema\_id   | int    | 订阅的数据表的 ID           |
| schema\_name | String | 订阅的数据表的表名            |
| id           | String | 新增的数据行的 ID           |
| after        | Map    | 新增的数据行对象             |
| before       | Map    | 空对象                  |

`update` 事件得到的 `WampCallback` 类型：

| 名称           | 类型     | 说明                   |
| ------------ | ------ | -------------------- |
| event        | String | 事件类型，返回 "on\_update" |
| schema\_id   | int    | 订阅的数据表的 ID           |
| schema\_name | String | 订阅的数据表的表名            |
| id           | String | 更新的数据行的 ID           |
| after        | Map    | 更新后的数据行对象            |
| before       | Map    | 更新前的数据行对象            |

`delete` 事件得到的 `WampCallback` 类型：

| 名称           | 类型     | 说明                   |
| ------------ | ------ | -------------------- |
| event        | String | 事件类型，返回 "on\_delete" |
| schema\_id   | int    | 订阅的数据表的 ID           |
| schema\_name | String | 订阅的数据表的表名            |
| id           | String | 删除的数据行的 ID           |
| after        | Map    | 空对象                  |
| before       | Map    | 删除前的数据行对象            |

通过上面的步骤，即可订阅某个数据表的其中一个数据变化动作（新增、更新或删除）的变化，具体操作阅读以下内容。

## 订阅数据表

**请求示例**

```dart
// 订阅 tableName 为 'product' 的数据表的新增数据动作
Future subscribeEvent(eventType) async {
  String tableName = 'product';
  TableObject tableObject = new TableObject(tableName);

  try {
    WampSubscriber createEvent = await tableObject.subscribe(
      eventType,
      onInit: () {
        print('订阅成功==>');
      },
      onEvent: (result) {
        print('订阅推送==> $eventType');
        print(result.event);
      },
      onError: (error) {
        print('订阅断开==>');
        print(error.message);
        print(error.details);
      },
    );
  } catch (e) {
    print(e.toString());
  }
}
```

**返回示例**

onevent 回调函数中的 res 对象结构如下：

数据表新增数据（create）返回的对象结构：

```json
{
  "after": {
    "text": "123",
    "_read_perm": ["user:anonymous"],
    "_write_perm": ["user:anonymous"],
    "created_at": 1594265027,
    "updated_at": 1594265027,
    "created_by": 195448780235670,
    "id": "5f068dc32dc610747781efcc"
  },
  "before": {},
  "event": "on_create",
  "schema_id": 968,
  "schema_name": "product",
  "id": "5f068dc32dc610747781efcc"
}
```

数据表更新数据（update）返回的对象结构：

```json
{
  "after": {
    "text": "123123",
    "_read_perm": ["user:anonymous"],
    "_write_perm": ["user:anonymous"],
    "created_at": 1594265027,
    "updated_at": 1594265113,
    "created_by": 195448780235670,
    "id": "5f068dc32dc610747781efcc"
  },
  "before": {
    "text": "123",
    "_read_perm": ["user:anonymous"],
    "_write_perm": ["user:anonymous"],
    "created_at": 1594265027,
    "updated_at": 1594265027,
    "created_by": 195448780235670,
    "id": "5f068dc32dc610747781efcc"
  },
  "event": "on_update",
  "schema_id": 968,
  "schema_name": "product",
  "id": "5f068dc32dc610747781efcc"
}
```

数据表删除数据（delete）返回的对象结构：

```json
{
  "after": {},
  "before": {
    "text": "123123",
    "_read_perm": ["user:anonymous"],
    "_write_perm": ["user:anonymous"],
    "created_at": 1594265027,
    "updated_at": 1594265113,
    "created_by": 195448780235670,
    "id": "5f068dc32dc610747781efcc"
  },
  "event": "on_delete",
  "schema_id": 968,
  "schema_name": "product",
  "id": "5f068dc32dc610747781efcc"
}
```

err 对象结构请参考[错误码和 HError 对象](/baas-js-sdk/flutter-sdk/error-code.md)

> **info** 当 WebSocket 连接意外断开时，SDK 会采用指数退避算法的机制，自动尝试重连。

另外，在知晓云控制台中手动删除数据时，如需触发删除数据动作的订阅通知，需要勾上「删除动作触发触发器」设置，如下图

![删除数据触发 WebSocket](/files/zO5DovlplVLCHLe06ONr)

## 按查询条件订阅

> **info** 条件订阅使用方法与查询数据（Where）一致，可参考：[查询数据](/baas-js-sdk/flutter-sdk/schema/query.md)。 Websocket 按条件订阅目前仅支持比较（compare）查询。

按条件订阅支持以下操作符：

| 数据类型    | 可使用的查询操作            | 说明 |
| ------- | ------------------- | -- |
| string  | =, !=               | -  |
| integer | =, >, >=, <, <=, != | -  |
| number  | =, >, >=, <, <=, != | -  |
| boolean | =, !=               | -  |
| date    | =, >, >=, <, <=, != | -  |

**请求示例**

```js
// 订阅 tableName 为 'product' 的数据表的新增数据动作
Future subscribeEvent(eventType) async {
  String tableName = 'product';
  TableObject tableObject = new TableObject(tableName);

  try {
    WampSubscriber createEvent = await tableObject.subscribe(
      eventType,
      onInit: () {
        print('订阅成功==>');
      },
      onEvent: (result) {
        print('订阅推送==> $eventType');
        print(result.event);
      },
      onError: (error) {
        print('订阅断开==>');
        print(error.message);
        print(error.details);
      },
      where: Where.compare('text', '=', 'hello'),
    );
  } catch (e) {
    print(e.toString());
  }
}
```

## 取消订阅

当实时数据库功能连接成功后，会一直保持订阅状态。如需断开连接，比如退出发起订阅的页面时，可根据需要主动发起取消订阅。

**请求示例**

```dart
createEvent.unsubscribe(); // 取消订阅上述示例中数据表的新增数据动作
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ifanr.gitbook.io/baas-js-sdk/flutter-sdk/schema/websocket.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
