跳到主要内容

操作

Deno KV 目前处于测试阶段

Deno 的 KV 及其相关的云基元 API,如队列和定时任务,目前仍处于实验性阶段,可能会发生变化。尽管我们尽力确保数据持久性,但特别是在 Deno 更新时,仍然存在数据丢失的可能性。

在启动使用 KV 的 Deno 程序时,需要添加--unstable标志,如下所示:

deno run -A --unstable my_kv_code.ts

Deno KV API 提供了一组可以在键空间上执行的操作。

有两个操作从存储中读取数据,还有五个操作将数据写入存储。

读操作可以在强一致性模式或最终一致性模式下执行。强一致性模式保证读取操作将返回最新写入的值。最终一致性模式可能返回陈旧值,但速度更快。

写操作始终在强一致性模式下执行。

get

get 操作返回与给定键关联的值和版本戳。如果值不存在,get 返回一个 null 值和版本戳。

有两个 API 可用于执行 get 操作。[Deno.Kv.prototype.get(key, options?)][get] API,用于读取单个键,以及 [Deno.Kv.prototype.getMany(keys, options?)][getMany] API,用于一次读取多个键。

在所有一致性模式中,Get 操作都作为 "快照读" 执行。这意味着一次检索多个键时,返回的值将与彼此一致。

const res = await kv.get<string>(["config"]);
console.log(res); // { key: ["config"], value: "value", versionstamp: "000002fa526aaccb0000" }

const res = await kv.get<string>(["config"], { consistency: "eventual" });
console.log(res); // { key: ["config"], value: "value", versionstamp: "000002fa526aaccb0000" }

const [res1, res2, res3] = await kv.getMany<[string, string, string]>([
["users", "sam"],
["users", "taylor"],
["users", "alex"],
]);
console.log(res1); // { key: ["users", "sam"], value: "sam", versionstamp: "00e0a2a0f0178b270000" }
console.log(res2); // { key: ["users", "taylor"], value: "taylor", versionstamp: "0059e9035e5e7c5e0000" }
console.log(res3); // { key: ["users", "alex"], value: "alex", versionstamp: "00a44a3c3e53b9750000" }

## `list`

`list` 操作返回与给定选择器匹配的键列表。还返回这些键的关联值和版本戳。有两种不同的选择器可用于过滤匹配的键。

`prefix` 选择器匹配以给定前缀键部分开头的所有键,但不包括键的确切匹配。前缀选择器可以选择性地给定 `start` 或 `end` 键以限制返回的键范围。`start` 键是包含的,`end` 键是排除的。

`range` 选择器匹配在给定 `start` 和 `end` 键之间的所有键。`start` 键是包含的,`end` 键是排除的。

> 注意:在前缀选择器的情况下,`prefix` 键必须仅由完整的键部分(而非部分键部分)组成。例如,如果存储中存在键 `["foo", "bar"]`,那么前缀选择器 `["foo"]` 会匹配它,但前缀选择器 `["f"]` 不会。

`list` 操作可以选择性地给定 `limit` 以限制返回的键数。

可以使用 [`Deno.Kv.prototype.list<string>(selector, options?)`][list] 方法执行列表操作。此方法返回一个 `Deno.KvListIterator`,可用于遍历返回的键。这是一个异步迭代器,可与 `for await` 循环一起使用。

```ts
// 返回所有用户
const iter = kv.list<string>({ prefix: ["users"] });
const users = [];
for await (const res of iter) users.push(res);
console.log(users[0]); // { key: ["users", "alex"], value: "alex", versionstamp: "00a44a3c3e53b9750000" }
console.log(users[1]); // { key: ["users", "sam"], value: "sam", versionstamp: "00e0a2a0f0178b270000" }
console.log(users[2]); // { key: ["users", "taylor"], value: "taylor", versionstamp: "0059e9035e5e7c5e0000" }

// 返回前两个用户
const iter = kv.list<string>({ prefix: ["users"] }, { limit: 2 });
const users = [];
for await (const res of iter) users.push(res);
console.log(users[0]); // { key: ["users", "alex"], value: "alex", versionstamp: "00a44a3c3e53b9750000" }
console.log(users[1]); // { key: ["users", "sam"], value: "sam", versionstamp: "00e0a2a0f0178b270000" }

// 返回所有字母介于 "a" 和 "n" 之间的用户
const iter = kv.list<string>({ start: ["users", "a"], end: ["users", "n"] });
const users = [];
for await (const res of iter) users.push(res);
console.log(users[0]); // { key: ["users", "alex"], value: "alex", versionstamp: "00a44a3c3e53b9750000" }
```

列表操作以批处理方式从存储中读取数据。每个批次的大小可以使用 `batchSize` 选项进行控制。默认的批次大小是 500 个键。批内的数据在单个快照读中读取,因此这些值彼此一致。一致性模式适用于每个数据批次。在批次之间,数据是不一致的。API 不会显示批次之间的边界,因为迭代器返回单个键。

`list` 操作可以通过将 `reverse` 选项设置为 `true` 来以倒序方式执行。这将以词法逆序返回键。`start` 和 `end

` 键仍然是包含的和排除的,仍然被解释为词法升序。

```ts
// 以倒序方式返回所有用户,以 "sam" 结尾
const iter = kv.list<string>(
{ prefix: ["users"], start: ["users", "sam"] },
{
reverse: true,
}
);
const users = [];
for await (const res of iter) users.push(res);
console.log(users[0]); // { key: ["users", "taylor"], value: "taylor", versionstamp: "0059e9035e5e7c5e0000" }
console.log(users[1]); // { key: ["users", "sam"], value: "sam", versionstamp: "00e0a2a0f0178b270000" }
```

> 注意:在上述示例中,我们将 `start` 键设置为 `["users", "sam"]`,尽管返回的第一个键是 `["users", "taylor"]`。这是因为 `start` 和 `end` 键始终按词法升序进行评估,即使列表操作是以倒序方式执行(以词法逆序返回键)。

## `set`

`set` 操作设置存储中键的值。如果键不存在,它将被创建。如果键已存在,其值将被覆盖。

`set` 操作可以使用 [`Deno.Kv.prototype.set(key, value)`][set] 方法执行。此方法返回一个 `Promise`,解析为 `Deno.KvCommitResult` 对象,其中包含提交的 `versionstamp`。

设置操作始终以强一致性模式执行。

```ts
const res = await kv.set(["users", "alex"], "alex");
console.log(res.versionstamp); // "00a44a3c3e53b9750000"
```

## `delete`

`delete` 操作从存储中删除键。如果键不存在,操作将不执行任何操作。

`delete` 操作可以使用 [`Deno.Kv.prototype.delete(key)`][delete] 方法执行。

删除操作始终以强一致性模式执行。

```ts
await kv.delete(["users", "alex"]);
```

## `sum`

`sum` 操作将值原子地添加到存储中的键。如果键不存在,它将使用和值创建。如果键已存在,则将其值添加到和值中。

`sum` 操作只能作为原子操作的一部分执行。可以使用 [`Deno.AtomicOperation.prototype.mutate({ type: "sum", value })`][mutate] 方法将总和变异添加到原子操作中。

`sum` 操作只能在 `Deno.KvU64` 类型的值上执行。键和存储中的值必须都是 `Deno.KvU64` 类型。

如果键的新值大于 `2^64 - 1` 或小于 `0`,则总和操作将循环。例如,如果存储中的值是 `2^64 - 1`,操作数是 `1`,则新值将是 `0`。

总和操作始终以强一致性模式执行。

```ts
await kv
.atomic()
.mutate({
type: "sum",
key: ["accounts", "alex"],
value: new Deno.KvU64(100n),
})
.commit();
```

## `min`

`min` 操作原子地将键设置为其当前值和给定值的最小值。如果键不存在,它将使用给定值创建。如果键已存在,则将其值设置为当前值和给定值的最小值。

`min` 操作只能作为原子操作的一部分执行。可以使用 [`Deno.AtomicOperation.prototype.mutate({ type: "min", value })`][mutate] 方法将最小变异添加到原子操作中。

`min` 操作只能在 `Deno.KvU64` 类型的值上执行。键和存储中的值必须都是 `Deno.KvU64` 类型。

最小操作始终以强一致性模式执行。

```ts
await kv
.atomic()
.mutate({
type: "min",
key: ["accounts", "alex"],
value: new Deno.KvU64(100n),
})
.commit();
```

## `max`

`max` 操作原子地将键设置为其当前值和给定值的最大值。如果键不存在,它将使用给定值创建。如果键已存在,则将其值设置为当前值和给定值的最大值。

`max` 操作只能作为原子操作的一部分执行。可以使用 [`Deno.AtomicOperation.prototype.mutate({ type: "max", value })`][mutate] 方法将最大变异添加到原子操作中。

`max` 操作只能在 `Deno.KvU64` 类型的值上执行。键和存储中的值必须都是 `Deno.KvU64` 类型。

最大操作始终以强一致性模式执行。

```ts
await kv
.atomic()
.mutate({
type: "max",
key: ["accounts", "alex"],
value: new Deno.KvU64(100n),
})
.commit();
```

[get]: https://deno.land/api?s=Deno.Kv&p=prototype.get&unstable
[getMany]: https://deno.land/api?s=Deno.Kv&p=prototype.getMany&unstable
[list]: https://deno.land/api?s=Deno.Kv&p=prototype.list&unstable
[set]: https://deno.land/api?s=Deno.Kv&p=prototype.set&unstable
[delete]: https://deno.land/api?s=Deno.Kv&p=prototype.delete&unstable
[mutate]: https://deno.land/api?s=Deno.AtomicOperation&p=prototype.mutate&unstable

```