跳到主要内容

更新数据

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);

状态属性

属性类型说明
localboolean若为 false 表示新创建未持久化;true 表示已存在于数据库
modifiedboolean实体是否有未保存的修改
targetT实体的当前值(Proxy 代理的原始对象)
remoteT | undefined远程同步的值(用于冲突检测)
patchesEntityPatch<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)