尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Convex 函数目录实战指南:从 query/mutation 基础到文件存储上传全链路

发布时间:2026/9/23 18:53:35

资讯中心
01
ARTICLE

Convex 函数目录实战指南:从 query/mutation 基础到文件存储上传全链路

Convex 函数目录实战指南:从 query/mutation 基础到文件存储上传全链路
数据库后端【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址https://gitcode.com/gh_mirrors/co/convex-backend点击查看免费下载本篇指南以 npm-packages/demos/file-storage/convex/README.md 中的 Convex 函数目录模板为核心骨架结合仓库内 File Storage 示例应用的完整源码系统讲解在 convex-backend 生态中如何编写 query 与 mutation 函数、如何在 React 客户端调用它们并完整拆解图片上传场景中生成上传 URL、POST 文件、保存存储 ID 的三步链路。读完本文你将能够独立搭建一个带文件上传能力的 Convex 函数目录并理解其背后的存储实现原理。一、函数目录是什么读懂模板 README 的定位每个 Convex 项目都会包含一个convex/函数目录在示例应用中即 npm-packages/demos/file-storage/convex它是你编写所有后端函数的唯一位置。目录顶部的README.md是一份官方生成的模板它的作用并非介绍某个业务而是快速教会新开发者两件事后端函数分两类query读数据支持订阅式实时更新与mutation写数据函数如何与前端衔接通过convex/_generated自动生成的 API 类型安全地暴露给客户端。该目录内还包含_generated/目录存放由 Convex CLI 自动生成的api.ts、server.ts、dataModel.ts等类型文件和 tsconfig.json。值得留意的是模板 README 中给出的tsconfig.json约束了函数目录的编译环境target: ESNext、lib: [ES2023, dom]、strict: true其中noEmit: true表示仅做类型检查真正的运行环境由 Convex 后端即本仓库的crates/下的 Rust 实现提供。说明模板中的代码示例myQueryFunction、myMutationFunction是教学骨架本仓库中的 messages.ts 则给出了这些骨架在实际业务中的完整形态。下面两节将两者对照讲解。二、编写 query 函数参数校验、读库与数据整形模板 README 给出的 query 函数骨架如下// convex/myFunctions.ts import { query } from ./_generated/server; import { v } from convex/values; export const myQueryFunction query({ // Validators for arguments. args: { first: v.number(), second: v.string(), }, // Function implementation. handler: async (ctx, args) { // Read the database as many times as you need here. const documents await ctx.db.query(tablename).collect(); // Arguments passed from the client are properties of the args object. console.log(args.first, args.second); // Write arbitrary JavaScript here: filter, aggregate, build derived data, // remove non-public properties, or create new objects. return documents; }, });该骨架包含三个必须理解的关键点args校验器Validatorsv.number()、v.string()来自convex/values由后端在调用边界强制校验保证客户端传入的参数类型与函数声明一致。这层校验最终由本仓库crates/udf等模块在运行时解析执行。handler中的ctx.dbquery 可以任意次读取数据库。ctx.db.query(tablename).collect()拉取整张表除此之外还支持.first()、.get(id)、.withIndex()等更精细的读取方式。返回值即API 响应handler 返回什么前端useQuery就能拿到什么——这给了你在服务端过滤敏感字段、聚合派生数据的空间。实战形态把存储 ID 转成可访问 URL在 File Storage 示例中真正的 query 函数list继承并强化了上述骨架见 messages.tsimport { v } from convex/values; import { query } from ./_generated/server; export const list query({ args: {}, handler: async (ctx) { const messages await ctx.db.query(messages).collect(); return Promise.all( messages.map(async (message) ({ ...message, // If the message is an image its body is an Id_storage ...(message.format image ? { url: await ctx.storage.getUrl(message.body) } : {}), })), ); }, });这里展示了两个骨架未涵盖的高级用法ctx.storage.getUrl(storageId)把存储在 Convex 文件存储中的文件 IDId_storage转换为可直接在浏览器中加载的 URL。这是存 ID、按需取 URL模式的核心 API。数据整形handler 内对每条消息做...message展开并针对format image的消息追加url字段其余文本消息原样返回——典型的派生数据写法。三、编写 mutation 函数写库并可选返回结果模板 README 给出的 mutation 骨架如下// convex/myFunctions.ts import { mutation } from ./_generated/server; import { v } from convex/values; export const myMutationFunction mutation({ // Validators for arguments. args: { first: v.string(), second: v.string(), }, // Function implementation. handler: async (ctx, args) { // Insert or modify documents in the database here. // Mutations can also read from the database like queries. const message { body: args.first, author: args.second }; const id await ctx.db.insert(messages, message); // Optionally, return a value from your mutation. return await ctx.db.get(messages, id); }, });要点mutation 与 query 的差异mutation 通过ctx.db.insert、ctx.db.replace、ctx.db.patch、ctx.db.delete修改文档同时也能像 query 一样读取数据库。ctx.db.insert返回新文档 ID随后可用ctx.db.get(messages, id)把刚写入的文档返回给客户端——可选返回值意味着前端可以await拿到写入结果。实战形态文本消息与图片消息两条写入路径messages.ts 给出了两种实际 mutationexport const sendImage mutation({ args: { storageId: v.id(_storage), author: v.string() }, handler: async (ctx, args) { await ctx.db.insert(messages, { body: args.storageId, author: args.author, format: image, }); }, }); export const sendMessage mutation({ args: { body: v.string(), author: v.string() }, handler: async (ctx, args) { const { body, author } args; await ctx.db.insert(messages, { body, author, format: text }); }, });两条 mutation 共用一张messages表通过format字段区分文本消息与图片消息sendMessagebody存文本format为textsendImagebody存的是一个v.id(_storage)类型的文件存储 IDformat为image。这种用_storage表的 ID 作为字段值的设计正是 Convex 文件存储与业务表关联的标准做法——文件实体本身由系统表_storage管理业务表只保存引用。四、客户端调用useQuery 与 useMutation模板 README 展示了 query/mutation 在 React 组件中的用法const data useQuery(api.myFunctions.myQueryFunction, { first: 10, second: hello, });const mutation useMutation(api.myFunctions.myMutationFunction); function handleButtonPress() { // fire and forget, the most common way to use mutations mutation({ first: Hello!, second: me }); // OR // use the result once the mutation has completed mutation({ first: Hello!, second: me }).then((result) console.log(result), ); }两个要点api是类型安全的自动生成对象api.myFunctions.myQueryFunction来自convex/_generated/apiCLI 会在每次convex dev/convex deploy时重新生成保证前后端签名一致。useMutation 的两种用法既可以fire and forget最常见也可以.then()消费返回值对应 mutation 的可选返回。实战形态图片上传的前端三步App.tsx 中的handleSendImage是完整的图片上传前端逻辑async function handleSendImage(event: FormEvent) { event.preventDefault(); // Step 1: Get a short-lived upload URL const postUrl await generateUploadUrl(); // Step 2: POST the file to the URL const result await fetch(postUrl, { method: POST, headers: { Content-Type: selectedImage!.type }, body: selectedImage, }); const json await result.json(); if (!result.ok) { throw new Error(Upload failed: ${JSON.stringify(json)}); } const { storageId } json; // Step 3: Save the newly allocated storage id to the database await sendImage({ storageId, author: name }); setSelectedImage(null); imageInput.current!.value ; }三步链路是 Convex 文件上传的标准模式Step 1调用 mutationgenerateUploadUrl()获取一个短时有效的上传 URL文件内容不经后端函数中转Step 2用浏览器fetch直接POST文件二进制到该 URL响应 JSON 中带回storageIdStep 3调用sendImagemutation把storageId与作者信息写入messages表。前端还配套了input typefile acceptimage/*文件选择控件以及一个把format image的消息渲染为img的Image组件App.tsxfunction Image({ message }: { message: { url: string } }) { return img src{message.url} height300px widthauto /; }如果你只想聚焦上传逻辑本身仓库还提供了只含上传表单的精简版本 src/_simpleApp.tsx可作为最小可运行参考。五、上传 URL 的底层原理短时授权令牌与存储端点前端拿到的上传 URL 并非固定不变的静态地址而是由后端按需签发。在 Rust 后端 crates/file_storage/src/core.rs 中generate_upload_url_with_origin的实现揭示了其结构pub fn generate_upload_url_with_origin( self, origin_override: OptionConvexOrigin, key_broker: FunctionRunnerKeyBroker, issued_ts: UnixTimestamp, component: ComponentId, ) - anyhow::ResultString { let token key_broker.issue_store_file_authorization(self.rt, issued_ts, component)?; let origin origin_override.unwrap_or_else(|| self.convex_origin.clone()); Ok(format!({origin}/api/storage/upload?token{token})) }可以从中提炼出三个实现事实URL 形如{origin}/api/storage/upload?token{token}origin是部署的 Convex 地址若配置了 canonical URL 会优先使用它见同文件中的CanonicalUrlsModel查询逻辑token是短时授权的核心由FunctionRunnerKeyBroker通过issue_store_file_authorization签发绑定到当前函数运行时的issued_ts签发时间戳与component组件 ID服务端在/api/storage/upload端点校验该令牌后才接受文件写入文件不经过函数执行器上传发生在存储服务与浏览器之间函数只负责发钥匙这也是大文件上传不会阻塞函数执行的原因。换句话说前端三步中的generateUploadUrlmutation 实际就是在服务端执行上述generate_upload_url把带令牌的 URL 返回给浏览器。六、运行与开发Convex CLI 的使用模板 README 末尾指出了 CLI 的两个入口命令需在项目根目录执行npx convex -hnpx convex -h查看 Convex CLI 全部可用子命令dev、deploy、dashboard、init、codegen等。npx convex docsnpx convex docs在本地启动官方文档服务。在 File Storage 示例中package.json 把convex dev与 Vite 前端开发服务器捆绑到了一起scripts: { dev: convex dev --start vite --open, build: tsc --noEmit vite build }按 npm-packages/demos/file-storage/README.md 的说明启动应用只需两步npm install npm run devconvex dev --start vite --open会同时启动本地 Convex 后端监视convex/目录并自动生成_generated类型与 Vite 前端开发服务器并自动打开浏览器。convex dev模式下修改messages.ts中的函数会自动热更新部署配合useQuery的订阅机制前端界面会实时反映数据库变化——这正是reactive database开发体验的直接体现。七、总结从模板到实战的完整路径回顾整条链路convex/README.md 这份模板看似简单却串联起了 Convex 开发的全部核心概念模板要点实战落地本仓库query 骨架与参数校验list查询消息并用ctx.storage.getUrl转换图片 URLmutation 骨架与可选返回sendMessage/sendImage写入文本与图片消息ReactuseQuery/useMutation调用App.tsx中的消息列表渲染与三步上传流程CLI 命令npx convex -h、npx convex docs、convex dev --start理解这份模板的意义在于它是进入任何 Convex 项目的第一道门。掌握 query/mutation 的编写规范、_generated自动类型的衔接方式以及存储 ID 入业务表 按需取 URL的文件存储模式后你就能在 npm-packages/demos/file-storage 的基础上继续扩展——例如加入图片缩略图、增加分页查询或接入其他存储场景而所有新函数都将遵循同一套目录组织与前后端衔接范式。赞分享数据库后端【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址https://gitcode.com/gh_mirrors/co/convex-backend点击查看免费下载相关推荐Convex 函数目录开发指南从零编写 Convex query 与 mutation 函数convex-backend 实战Convex 函数目录开发指南从零编写 Convex query 与 mutation 函数convex backend 实战 本指南以 convex b数据库后端Convex 函数开发实战从 Query/Mutation 基础到全文搜索基于 convex-backend 仓库 search 示例Convex 函数开发实战从 Query/Mutation 基础到全文搜索基于 convex backend 仓库 search 示例 导读 本文以 co数据库后端从函数模板到 TanStack Start 实战Convex 函数目录 query/mutation 全解析从函数模板到 TanStack Start 实战Convex 函数目录 query/mutation 全解析 本文围绕 TanStack Start 全栈快速数据库后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。