# 数据存储
## 文档存储服务简介

云文档小组件提供了强大的数据存储服务，除了常规的数据存储服务，还集成协同解决方案。存储服务还跟文档整体有很高的贴合度，数据变更文档的操作逻辑，如：数据可以通过历史记录还原等。

## 使用场景说明

我们提供了两种数据存储方案，分别是「文档数据」「互动数据」，两者在存储能力上一致，但在权限、功能特性上有差异，开发者可以根据不同的业务场景选择所需的存储服务。

### 场景一、类投票场景

需要记录用户操作行为的场景，如云文档中「信息收集」「投票」功能，配置类的数据需要使用「文档数据」或「互动数据」均可以，但用户点击列表数据**必须**使用「互动数据」，因为「文档数据」是需要当前用户拥有写入权限的，而投票这个行为是阅读权限也可以执行的。

### 场景二、文本编辑类型场景

文本编辑类型场景，建议使用「文档数据」进行存储，「文档数据」天然接入了云文档的撤销/重做、历史记录，让编辑行为更贴近文档操作。
![image.png](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/3a772e78b954ac8c38b6a83fcf31847a_wGyV0qzJdx.png?lazyload=true&width=2644&height=1250)

### 场景三、需要自定义复制粘贴数据

「文档数据」「互动数据」的数据拷贝策略是不一样的，如果你希望复制前后一样，那你需要使用「文档数据」，如果你希望复制后数据被清空，「互动数据」是你的选择。

### 如何选择你需要的服务

往往真实场景时「文档数据」「互动数据」混合使用的，关键的决策点是根据需求场景来决定的，正如我们上面举例子的场景，有些数据使用任意存储服务均可以，投票动作就必须使用「互动数据」。

## 功能详细介绍

| 存储服务名称    | 文档数据                                                                                 | 互动数据                                                                                 |
| --------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| 对应 API    | [Record](https://open.feishu.cn/document/uAjLw4CM/uYjL24iN/docs-add-on/05-api-doc/basic-data-reference---base/Record.getRecord)               | [Interaction](https://open.feishu.cn/document/uAjLw4CM/uYjL24iN/docs-add-on/05-api-doc/basic-data-reference---base/Interaction.getData)          |
| 支持组件类型    | -   正文小组件&其附属视图 - [详见](https://open.feishu.cn/document/uAjLw4CM/uYjL24iN/docs-add-on/02-cloud-doc-block-noun-explanation) | -   正文小组件&其附属视图 - [详见](https://open.feishu.cn/document/uAjLw4CM/uYjL24iN/docs-add-on/02-cloud-doc-block-noun-explanation) |
| 数据体积      | 500KB                                                                                | 500KB                                                                                |
| 协同能力      | 支持                                                                                   | 支持                                                                                   |
| 冲突解决能力    | 支持                                                                                   | 支持                                                                                   |
| 权限要求      | 需要当前用户有文档编辑权限                                                                        | 无约束                                                                                  |
| 支持历史记录还原  | 支持                                                                                   | 不支持                                                                                  |
| 支持正文撤销/重做 | 支持                                                                                   | 不支持                                                                                  |
| 数据拷贝行为    | 数据深拷贝，详见后面复制行为说明章节                                                                   | 数据清空                                                                                 |

### 复制行为说明

特别说明数据拷贝行为，「文档数据」进行数据拷贝时，是创建一个全新的数据实体，并且将数据重新复制一份至新的数据实体当中；下面用伪代码举例说明。
```js
// 原数据
originData = {
    record_id: 'origin_id', // 这是文档数据实体id
    data: { // 这是三方数据
        config: { color: 'red', time: '2023-1-18' }
    }
} 
```
我们将原数据复制粘贴后，会变成下面这样
```js
// 克隆数据
cloneData = {
    record_id: 'clone_origin_id', // 这是文档数据实体id
    data: { // 这是三方数据
        config: { color: 'red', time: '2023-1-18' }
    }
} 
```

### 如何使用协同能力

> 这里用「文档数据」来举例说明，
开发者无需关注底层协同算法，开发者按照 API 传参格式告诉文档数据要如何操作即可，下面通过简单的伪代码说明，协同使用方式和协同的效果。

**步骤1.** 假设应用在A文档存储了版本号为1数据块；`data = { root: { a:1, b: 1 } }`;

**步骤2.** 有一个用户小明，在版本号为1数据块提交了一个数据更新的操作；在root 对象下**新增 c=1 数据**；伪代码如下：
```js
DocMiniApp.Record.setRecord([
    {
      type: 'insert',
      data: {
        path: ['root', 'c' ],
        value: 1
      }
    }
  ]);
```

**步骤3.** 有一个用户小白，在版本号为1数据块提交了一个数据删除的操作；在root 对象下**删除b数据**；伪代码如下：
```js
DocMiniApp.Record.setRecord([
    {
      type: 'remove',
      data: {
        path: ['root', 'b' ],
        value: 1
      }
    }
  ]);
```
**步骤4.** 最终小明与小白得到的数据块是： `data = { root: { a:1, c: 1 } };`