跳到主要内容

findOne

查找符合条件的第一个实体,如果未找到则返回 undefined

方法签名

findOne(options: FindOneOptions<T>): Observable<InstanceType<T> | undefined>

参数说明

interface FindOneOptions<T> {
// 查询条件
where: RuleGroup<InstanceType<T>>;

// 排序条件(可选)
orderBy?: OrderBy[];
}

使用场景

1. 根据条件查找单个实体

import { firstValueFrom, switchMap } from 'rxjs';

// 查找特定 ID 的 todo
const todo = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{
field: 'id',
operator: '=',
value: '591e97aa-f7e3-499c-9fa4-4e2ae4459ef6'
}
]
}
})),
firstValueFrom
);

if (todo) {
console.log('找到 todo:', todo.title);
} else {
console.log('未找到 todo');
}

2. 查找最新创建的记录

const latestTodo = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: []
},
orderBy: [
{ field: 'createdAt', sort: 'desc' }
]
})),
firstValueFrom
);

3. 查找特定用户的第一个待办事项

const userFirstTodo = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{
field: 'userId',
operator: '=',
value: 'user-123'
},
{
field: 'completed',
operator: '=',
value: false
}
]
},
orderBy: [
{ field: 'priority', sort: 'desc' },
{ field: 'createdAt', sort: 'asc' }
]
})),
firstValueFrom
);

4. 使用复杂条件查询

const urgentIncompleteTodo = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{
field: 'completed',
operator: '=',
value: false
},
{
combinator: 'or',
rules: [
{
field: 'priority',
operator: '=',
value: 'high'
},
{
field: 'dueDate',
operator: '<',
value: new Date()
}
]
}
]
}
})),
firstValueFrom
);

5. 在组件中使用

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
selector: 'app-todo-detail',
template: `
<div *ngIf="todo$ | async as todo; else notFound">
<h2>{{ todo.title }}</h2>
<p>{{ todo.description }}</p>
</div>
<ng-template #notFound>
<p>未找到待办事项</p>
</ng-template>
`
})
export class TodoDetailComponent implements OnInit {
todo$!: Observable<Todo | undefined>;

ngOnInit() {
this.todo$ = rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{
field: 'id',
operator: '=',
value: this.todoId
}
]
}
}))
);
}
}

findOne vs findOneOrFail

方法未找到时行为返回类型使用场景
findOne返回 undefinedObservable<T | undefined>允许结果为空的查询
findOneOrFail抛出错误Observable<T>期望必定存在的查询
// findOne - 处理可能不存在的情况
const todo = await rxdb.pipe(
switchMap(() => Todo.findOne({ where: { ... } })),
firstValueFrom
);
if (todo) {
// 处理找到的情况
} else {
// 处理未找到的情况
}

// findOneOrFail - 不存在时抛出错误
try {
const todo = await rxdb.pipe(
switchMap(() => Todo.findOneOrFail({ where: { ... } })),
firstValueFrom
);
// 确定 todo 存在
} catch (error) {
// 处理错误
}

性能优化建议

1. 使用索引字段查询

// ✅ 好:使用主键或索引字段
Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'id', operator: '=', value: 'xxx' }
]
}
});

// ⚠️ 慢:使用非索引字段
Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'description', operator: 'contains', value: 'keyword' }
]
}
});

2. 添加合适的 orderBy

如果查询结果可能有多条,添加 orderBy 可以确保返回一致的结果:

Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'userId', operator: '=', value: 'user-123' }
]
},
orderBy: [
{ field: 'createdAt', sort: 'desc' }
]
});

常见用例

检查记录是否存在

const exists = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'title', operator: '=', value: '重复的标题' }
]
}
})),
map(todo => !!todo),
firstValueFrom
);

获取默认值

const todo = await rxdb.pipe(
switchMap(() => Todo.findOne({
where: {
combinator: 'and',
rules: [
{ field: 'id', operator: '=', value: todoId }
]
}
})),
map(todo => todo ?? createDefaultTodo()),
firstValueFrom
);

参考