get
根据 ID 直接获取实体,这是最简单、最高效的查询方式。
方法签名
get(id: EntityIdType): Observable<InstanceType<T>>
使用场景
1. 基础用法
import { firstValueFrom, switchMap } from 'rxjs';
// 根据 ID 获取 todo
const todo = await rxdb.pipe(
switchMap(() => Todo.get('591e97aa-f7e3-499c-9fa4-4e2ae4459ef6')),
firstValueFrom
);
console.log(todo.title);
2. 在组件中使用
import { Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
selector: 'app-todo-detail',
template: `
<div *ngIf="todo$ | async as todo">
<h2>{{ todo.title }}</h2>
<p>{{ todo.description }}</p>
<p>状态: {{ todo.completed ? '已完成' : '未完成' }}</p>
</div>
`
})
export class TodoDetailComponent implements OnInit {
@Input() todoId!: string;
todo$!: Observable<Todo>;
ngOnInit() {
this.todo$ = rxdb.pipe(
switchMap(() => Todo.get(this.todoId))
);
}
}
3. React 中使用
import { useEffect, useState } from 'react';
import { firstValueFrom, switchMap } from 'rxjs';
function TodoDetail({ todoId }: { todoId: string }) {
const [todo, setTodo] = useState<Todo | null>(null);
useEffect(() => {
const subscription = rxdb.pipe(
switchMap(() => Todo.get(todoId))
).subscribe(setTodo);
return () => subscription.unsubscribe();
}, [todoId]);
if (!todo) return <div>加载中...</div>;
return (
<div>
<h2>{todo.title}</h2>
<p>{todo.description}</p>
</div>
);
}
4. Vue 中使用
<template>
<div v-if="todo">
<h2>{{ todo.title }}</h2>
<p>{{ todo.description }}</p>
</div>
<div v-else>加载中...</div>
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
import { firstValueFrom, switchMap } from 'rxjs';
const props = defineProps<{ todoId: string }>();
const todo = ref<Todo | null>(null);
watchEffect(async () => {
const subscription = rxdb.pipe(
switchMap(() => Todo.get(props.todoId))
).subscribe(value => {
todo.value = value;
});
return () => subscription.unsubscribe();
});
</script>
5. 批量获取
// 批量获取多个实体
const todoIds = ['id-1', 'id-2', 'id-3'];
const todos = await Promise.all(
todoIds.map(id =>
rxdb.pipe(
switchMap(() => Todo.get(id)),
firstValueFrom
)
)
);
6. 结合错误处理
import { catchError, of } from 'rxjs';
const todo$ = rxdb.pipe(
switchMap(() => Todo.get(todoId)),
catchError(error => {
console.error('获取 todo 失败:', error);
return of(null);
})
);
get vs findOne
| 方法 | 查询方式 | 性能 | 参数 | 返回值 |
|---|---|---|---|---|
get | 主键索引 | 最快 | 仅需要 ID | Observable<T> |
findOne | 条件查询 | 较慢 | 复杂查询条件 | Observable<T | undefined> |
// get - 适合已知 ID 的情况
const todo1 = await rxdb.pipe(
switchMap(() => Todo.get('todo-id')),
firstValueFrom
);
// findOne - 适合需要条件查询的情况
const todo2 = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'userId', operator: '=', value: 'user-123' },
{ field: 'completed', operator: '=', value: false }
]
}
})),
firstValueFrom
);
性能优化
1. 使用 get 而非 findOne
当你已经知道实体的 ID 时,始终优先使用 get 而不是 findOne:
// ✅ 好:直接通过 ID 获取
Todo.get(todoId);
// ❌ 不必要的复杂:使用 findOne 查询 ID
Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'id', operator: '=', value: todoId }
]
}
});
2. 缓存策略
实体获取后会被缓存,重复调用 get 时会直接返回缓存的实体引用:
// 第一次调用会从数据库读取
const todo1 = await rxdb.pipe(
switchMap(() => Todo.get(todoId)),
firstValueFrom
);
// 第二次调用会返回相同的实体引用
const todo2 = await rxdb.pipe(
switchMap(() => Todo.get(todoId)),
firstValueFrom
);
console.log(todo1 === todo2); // true - 相同的对象引用
3. 响应式更新
使用 Observable 订阅,当实体更新时自动收到通知:
const subscription = rxdb.pipe(
switchMap(() => Todo.get(todoId))
).subscribe(todo => {
console.log('Todo 更新了:', todo);
});
// 在其他地方更新这个 todo
await Todo.update(todo, { completed: true });
// 上面的订阅会自动收到更新后的 todo
错误处理
ID 不存在时的处理
import { catchError, EMPTY } from 'rxjs';
// 方式 1: 使用 catchError 捕获错误
const todo$ = rxdb.pipe(
switchMap(() => Todo.get(todoId)),
catchError(error => {
if (error.code === 'ENTITY_NOT_FOUND') {
console.log('Todo 不存在');
return EMPTY;
}
throw error;
})
);
// 方式 2: 使用 try-catch
try {
const todo = await rxdb.pipe(
switchMap(() => Todo.get(todoId)),
firstValueFrom
);
} catch (error) {
console.error('获取失败:', error);
}
常见用例
1. 路由参数获取实体
import { ActivatedRoute } from '@angular/router';
import { switchMap } from 'rxjs';
@Component({
selector: 'app-todo-detail'
})
export class TodoDetailComponent {
todo$ = this.route.params.pipe(
switchMap(params => Todo.get(params['id']))
);
constructor(private route: ActivatedRoute) {}
}
2. 实时数据同步
// 订阅实体变化,实现实时更新
const todoSubscription = rxdb.pipe(
switchMap(() => Todo.get(todoId))
).subscribe(todo => {
// 每当这个 todo 在数据库中被更新时
// 这里会自动收到最新的数据
updateUI(todo);
});
3. 预加载相关数据
// 获取 todo 并预加载相关的用户信息
const todoWithUser$ = rxdb.pipe(
switchMap(() => Todo.get(todoId)),
switchMap(todo =>
User.get(todo.userId).pipe(
map(user => ({ todo, user }))
)
)
);
最佳实践
- 优先使用 get:当有 ID 时,始终使用
get而不是findOne - 利用缓存:理解实体缓存机制,避免不必要的重复查询
- 响应式编程:使用 Observable 订阅而非 Promise,享受自动更新的好处
- 错误处理:始终处理实体不存在的情况
- 类型安全:利用 TypeScript 类型推断,避免类型错误
参考
- findOne - 根据条件查找单个实体
- findOneOrFail - 查找单个实体,找不到抛出错误
- find - 查询多个实体