更新数据
RxDB 通过 Proxy 自动跟踪属性变更,配合 save() 实现高效的增量更新。
自动变更跟踪
所有通过 RxDB 管理的实体都是 Proxy 对象。修改属性时,Proxy 会自动记录变更:
const todo = await firstValueFrom(Todo.findOne({ where: { id: 1 } }));
// 直接修改属性,Proxy 自动拦截
todo.title = '更新后的标题';
todo.completed = true;
// 保存变更,只发送修改的字段
await todo.save();
实体状态
每个实体都有关联的 EntityStatus,可以通过 getEntityStatus() 获取:
import { getEntityStatus } from '@aiao/rxdb';
const status = getEntityStatus(todo);
状态属性
| 属性 | 类型 | 说明 |
|---|---|---|
local | boolean | 若为 false 表示新创建未持久化;true 表示已存在于数据库 |
modified | boolean | 实体是否有未保存的修改 |
target | T | 实体的当前值(Proxy 代理的原始对象) |
remote | T | undefined | 远程同步的值(用于冲突检测) |
patches | EntityPatch<T>[] | 变更补丁记录列表 |
变更补丁 (Patch)
每次属性修改都会生成一个 EntityPatch:
interface EntityPatch<T> {
patch: Partial<T>; // 正向补丁(新值)
inversePatch: Partial<T>; // 反向补丁(旧值,用于撤销)
recordAt: string; // 记录的属性路径
timeStamp: number; // 时间戳
}
使用 Repository 更新
通过 Repository.update() 直接更新:
const todo = await firstValueFrom(Todo.findOne({ where: { id: 1 } }));
todo.title = '新标题';
// 通过 Repository 更新
await Todo.update(todo);
智能跳过
EntityManager.update() 内部会检查 status.modified。如果实体没有任何修改,更新操作会被直接跳过,避免无意义的数据库写入。
重置修改
如果想撤销未保存的修改,可以调用 reset():
const todo = await firstValueFrom(Todo.findOne({ where: { id: 1 } }));
todo.title = '临时修改';
// status.modified === true
// 重置到最后保存的状态
todo.reset();
// status.modified === false,title 恢复原值
reset() 通过实体原型方法调用 EntityManager 的重置逻辑,将实体恢复到上次持久化的状态。
批量更新
使用 saveMany() 批量保存修改:
const todos = await firstValueFrom(Todo.findMany({ where: { completed: false } }));
// 批量修改
todos.forEach(todo => {
todo.completed = true;
});
// 一次性保存所有变更
await rxdb.entityManager.saveMany(todos);
saveMany() 将所有变更合并到一个 mutations 调用中,减少数据库交互次数。
原型方法注入
EntityManager 在初始化实体时,会通过 PROTOTYPE_METHODS 向实体原型注入便捷方法:
| 方法 | 说明 |
|---|---|
save() | 保存实体(自动判断 create/update) |
remove() | 删除实体 |
reset() | 重置未保存的修改 |
// 这些方法在实体上直接可用
const todo = new Todo({ title: '测试' });
await todo.save(); // EntityManager.save(todo)
await todo.remove(); // EntityManager.remove(todo)
todo.reset(); // EntityManager.reset(todo)