Convex 硬化柜台组件
此组件为 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读取.
- 当增量或减量时, 更多的硬块 更大的吞吐量.
- 查询计数时, 较慢的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.
如果你想要的不只是一个数, 看一下 合计部分。 。 。 .
有三种方法可以保持一个计数和表同步:
- 在插入或 从表格中删除.
- [建议] 将全部写入单独的 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");
}
- 登记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 实例/会议/实例。 。 。 .
步进:
- 更改现场留言更新计数器. 举个例子,你会
变化
insertUserBeforeBackfill将作为insertUserAfterBackfill。 。 。 . - 写入一个回填, 计算代码之前创建的文档
(1) 部署。 举例来说,这将是
backfillOldUsers。 。 。 . - 运行
backfillOldUsers从仪表板.
复杂的回填: 如果文档可能被删除
Ưμ㼯A 实例/会议/实例。 。 。 .
步进:
- 创建
backfillCursor以图示显示的表格 - 在此表格中创建有字段的新文档
{ creationTime: 0, id: "", isDone: false } - 任何您想要根据文档更改更新一个计数器的地方,请将
以条件更新, 只有在返回填充时才更新
处理该文件。 举个例子,你会改变
insertUserBeforeBackfill将作为insertUserDuringBackfill。 。 。 . - 定义类似于
backfillUsers财务报告和审定财务报表backfillUsersBatch - 打电话
backfillUsersBatch从仪表板. - 删除更新计数器时的条件 。 举个例子,你会
变化
insertUserDuringBackfill将作为insertUserAfterBackfill。 。 。 . - 删除
backfillCursor页:1.