@convex-dev/sharded-counter

中文文档
0.2.3发布于 2026/10/10Apache-2.0TypeScriptES Module零依赖近 30 天下载 46.6万

Convex的硬化计数器组件.

中文使用文档
文档目录9 节
  1. 预先要求: Convex
  2. 安装
  3. 更新和阅读计数器
  4. 压倒柜台
  5. 在读取时减少争议
  6. 计算表格中的文档
  7. 返回已存在的计数
  8. 简单的后补: 如果表格是附件
  9. 复杂的回填: 如果文档可能被删除

Convex 硬化柜台组件

npm version

此组件为 Convex 添加了计数器. 它扮演着从字符串来的密钥价值商店 改为数字,在更新值时会硬化以增加通量.

由于它是建立在 Convex上, 一切都是自动一致,反应, 并缓存。 因为它的建造与 构成部分, (中文(简体) ), 操作是孤立的,即使运行在 平行.

例如,如果想要显示 100万个复选框 在您的 Convex 网站上时,你想 实时计数复选框,同时允许许多框更改 平行.

更一般地说,每当你有一个柜台 经常改变,你可以 使用此组件以有效跟踪.

export const checkBox = mutation({
  args: { i: v.number() },
  handler: async (ctx, args) => {
    const checkbox = await ctx.db
      .query("checkboxes")
      .withIndex("i", (q) => q.eq("i", args.i))
      .unique();
    if (!checkbox.isChecked) {
      await ctx.db.patch(checkbox._id, { isChecked: true });

      // Here we increment the number of checkboxes.
      await numCheckboxes.inc(ctx);
    }
  },
});
export const getCount = query({
  args: {},
  handler: async (ctx, _args) => {
    return await numCheckboxes.count(ctx);
  },
});

这取决于你需要经常修改计数器的假设, 但只需从查询中读取其值,或者在突变中不经常读取. 若为 你每次修改时都会读取计数, 你就会失去硬化的好处.

预先要求: Convex

你需要一个现有的 Convex 项目来使用组件。 Convex 是一个主机 后端平台,包括数据库、无服务器功能和多一个吨 可以学习 这里。 。 。 .

运行 npm create convex 或遵循其中任何一条 快速启动 来设置一个.

安装

首先,安装组件包:

npm install @convex-dev/sharded-counter

然后,创建一个 convex.config.ts 应用程序中的文件 convex/ 文件夹和 通过调用安装组件 use数字 :

// convex/convex.config.ts
import { defineApp } from "convex/server";
import shardedCounter from "@convex-dev/sharded-counter/convex.config.js";

const app = defineApp();
app.use(shardedCounter);

export default app;

最后,创建一个新的 ShardedCounter 在您内部 convex/ 文件夹和点 转到已安装的组件.

import { components } from "./_generated/api";
import { ShardedCounter } from "@convex-dev/sharded-counter";

const counter = new ShardedCounter(components.shardedCounter);

更新和阅读计数器

一旦你有一个 ShardedCounter,有几种方法可以用来更新 在变异或动作中键的计数器.

await counter.add(ctx, "checkboxes", 5); // increment by 5
await counter.inc(ctx, "checkboxes"); // increment by 1
await counter.subtract(ctx, "checkboxes", 5); // decrement by 5
await counter.dec(ctx, "checkboxes"); // decrement by 1
await counter.reset(ctx, "checkboxes"); // reset to 0

const numCheckboxes = counter.for("checkboxes");
await numCheckboxes.inc(ctx); // increment
await numCheckboxes.dec(ctx); // decrement
await numCheckboxes.add(ctx, 5); // add 5
await numCheckboxes.subtract(ctx, 5); // subtract 5
await numCheckboxes.reset(ctx); // reset to 0

你可以在查询、变异或动作中读取计数器的价值.

await counter.count(ctx, "checkboxes");
await numCheckboxes.count(ctx);

更多实例使用 实例.ts。 。 。 .

压倒柜台

当单一文档同时被两个变异修改时 变异缓慢实现 可序列结果。 。 。 .

为了实现高吞吐量,ShardedCounter将计数分配到 多个文件,称为"硬". 增减 随机更新 shard,而总数的查询则从所有shards读取.

  1. 当增量或减量时, 更多的硬块 更大的吞吐量.
  2. 查询计数时, 较慢的shards QQ 更耐久 .

您可以在初始化 ShardedCounter 时设置硬体数 专门为每个密钥设置 :

const counter = new ShardedCounter(components.shardedCounter, {
  shards: { checkboxes: 100 }, // 100 shards for the key "checkboxes"
});

或者通过设置一个适用于未在 shards数字 :

const counter = new ShardedCounter(components.shardedCounter, {
  shards: { checkboxes: 100 },
  defaultShards: 8,
});

如果没有指定硬币的默认数为16.

注意您的密钥可以是字符串的子类型 。 例如,如果您想要存储一个数 每个用户的朋友, 而你不在乎通过量 对于一个用户, 你会这样宣布ShardedCounter:

const friendCounts = new ShardedCounter<Id<"users">>(
  components.shardedCounter,
  { defaultShards: 1 },
);

// Decrement a user's friend count by 1
await friendsCount.dec(ctx, userId);

在读取时减少争议

读取计数符 counter.count(ctx, "checkboxes") 读取所有硬体 以获得准确的计数。 这需要读取对所有硬文档的依赖.

  • 在查询订阅中,这意味着对计数器的任何更改都会引起查询 重新运行.
  • 在变异中,这意味着对计数器的任何修改都会导致 OCC 操作控制中心 冲突.

您可以通过估计计数来减小争议:从较小的数中读取 硬度和推论基于硬度的总数.

const estimatedCheckboxCount = await counter.estimateCount(ctx, "checkboxes");

默认情况下,它来自一个单随机的硬度和乘以总数 要构成估计数的硬点数。 你可以通过阅读来改进估计 以更多争议为代价:

const estimateFromThree = await counter.estimateCount(ctx, "checkboxes", 3);

如果柜台是从很多小堆积起来的 counter.inc 财务报告和审定财务报表 counter.dec 电话,那么它们应该统一分布 在硬体之间,如此估计 数将准确.

在某些情况下,柜台不会平均分配:

  • 如果柜台是少数操作累积的
  • 如果有些行动 counter.adds 或 (简体中文) counter.subtracts 有大块 值,因为每个操作只改变一个硬度
  • 如果沙子数量改变

在这种情况下,计数可能无法平均地分布在硬盘上. 改为: 您可拨打:

await counter.rebalance(ctx, "checkboxes");

连数数都算不上.

您可以更改第二个参数, 更改一个密钥的硬度数 页:1 ShardedCounter 建筑师。 如果你减少硬块的数量,你 将留下额外的硬块,这些硬块不会被写到,但仍被读取 计算 count。在这种情况下,你应该打电话 counter.rebalance 删除 外相的硬块.

注: counter.rebalance 读和写所有的shards, 这样可以引起更多的 OCCs,它被推荐为 节制,从Convex仪表板或 从不常见的克伦.

注:计数为浮点数,而浮点算术并非无限精确. 即使你总是加减整数, 你可能会得到一个分数, 特别是如果你使用 estimateCount 或者说 rebalance. 分布在各地的价值 硬体可以以不同的组合添加 浮点算术不是关联。 。 。 . 你用得着 Math.round 如果需要,可确保您的最终数是整数.

计算表格中的文档

您通常想要使用一个被打磨的计数器来跟踪文档中有多少 页:1.

如果你想要的不只是一个数, 看一下 合计部分。 。 。 .

有三种方法可以保持一个计数和表同步:

  1. 在插入或 从表格中删除.
  2. [建议] 将全部写入单独的 TypeScript 函数中的表格, 并总是将这些函数从变异调取出而不是写到 db 直接说 建议采用这种方法,因为它概括了逻辑 更新表格,同时保持所有操作清晰。 譬如说,
// Example of a mutation that calls `insertUser`.
export const insertPair = mutation(async (ctx) => {
  ...
  await insertUser(ctx, user1);
  await insertUser(ctx, user2);
});

// All inserts to the "users" table go through this function.
async function insertUser(ctx, user) {
  await ctx.db.insert("users", user);
  await counter.inc(ctx, "users");
}
  1. 登记a 触发, (中文(简体) ), 当一个突变改变表格中的数据时,它自动运行代码.
// Triggers hook up writes to the table to the ShardedCounter.
const triggers = new Triggers<DataModel>();
triggers.register("mytable", counter.trigger("mycounter"));
export const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB));

这个 插入用户与调试器 突变使用扳机.

返回已存在的计数

如果您想在表格中计数像文档的项目, 您可能已经有 在安装ShardedCounter组件之前,文档,这些组件应该是 记着.

简便的版本是计算一次值并添加该值,如果 还没有主动的请求发生。 您也可以定期重新计算 如果在飞行中没有要求,则更新计数器的价值.

棘手的部分是处理请求时进行计算:确保 将活动更新合并为要返回填充的旧值.

简单的后补: 如果表格是附件

Ưμ㼯A 实例/会议/实例。 。 。 .

步进:

  1. 更改现场留言更新计数器. 举个例子,你会 变化 insertUserBeforeBackfill 将作为 insertUserAfterBackfill。 。 。 .
  2. 写入一个回填, 计算代码之前创建的文档 (1) 部署。 举例来说,这将是 backfillOldUsers。 。 。 .
  3. 运行 backfillOldUsers 从仪表板.

复杂的回填: 如果文档可能被删除

Ưμ㼯A 实例/会议/实例。 。 。 .

步进:

  1. 创建 backfillCursor 以图示显示的表格
  2. 在此表格中创建有字段的新文档 { creationTime: 0, id: "", isDone: false }
  3. 任何您想要根据文档更改更新一个计数器的地方,请将 以条件更新, 只有在返回填充时才更新 处理该文件。 举个例子,你会改变 insertUserBeforeBackfill 将作为 insertUserDuringBackfill。 。 。 .
  4. 定义类似于 backfillUsers 财务报告和审定财务报表 backfillUsersBatch
  5. 打电话 backfillUsersBatch 从仪表板.
  6. 删除更新计数器时的条件 。 举个例子,你会 变化 insertUserDuringBackfill 将作为 insertUserAfterBackfill。 。 。 .
  7. 删除 backfillCursor 页:1.

版本与发布记录

@convex-dev/sharded-counter 共发布 12 个版本,首次发布于 2024/10/17;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.2.3latest2026/10/101 个月前
0.2.22026/10/071 个月前
0.2.12026/06/254 个月前
0.2.02025/11/1311 个月前
0.1.82025/05/311.4 年前
0.1.72025/02/061.8 年前

关于 @convex-dev/sharded-counter 的常见问题

@convex-dev/sharded-counter 是什么?

Convex的硬化计数器组件.

如何安装 @convex-dev/sharded-counter?

在项目目录运行 npm install @convex-dev/sharded-counter,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:convex(^1.25.4)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@convex-dev/sharded-counter 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@convex-dev/sharded-counter 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@convex-dev/sharded-counter 可以商用吗?

@convex-dev/sharded-counter 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@convex-dev/sharded-counter 的下载量有多少?

根据 npm 官方下载统计,@convex-dev/sharded-counter 在 2026/10/11 – 2026/11/09 这 30 天内被下载 465,782 次,日均约 15,526 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@convex-dev/sharded-counter 还在维护吗?

最新版本 0.2.3 发布于 2026/10/10(1 个月前);至今共发布 12 个版本,其中过去 12 个月发布了 4 个;首次发布于 2024/10/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。