ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LanceDB Node.js 表枚举指南:从弃用的 TableNamesOptions 迁移到 listTables 分页

2026/9/23 18:50:55 拓冰建站 浏览量
LanceDB Node.js 表枚举指南:从弃用的 TableNamesOptions 迁移到 listTables 分页 LanceDB Node.js 表枚举指南从弃用的 TableNamesOptions 迁移到 listTables 分页【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址: https://gitcode.com/gh_mirrors/la/lancedb导读TableNamesOptions是 LanceDB Node.js SDK 中用于控制列出数据库中所有表行为的选项接口。随着 SDK 演进该接口已被标记为 Deprecated弃用取而代之的是基于不透明pageToken的新分页方案ListTablesOptionsConnection.listTables。本文以该接口为切入点完整讲解旧接口的字段语义与分页用法、迁移到新 API 的具体步骤、底层 Rust 实现原理以及测试用例验证帮助你写出健壮、可维护的表枚举代码。TableNamesOptions 是什么在 nodejs/lancedb/connection.ts 中TableNamesOptions被定义为Connection.tableNames()方法的可选参数类型/** * deprecated Use {link ListTablesOptions} with {link Connection.listTables} * instead. */ export interface TableNamesOptions { /** * If present, only return names that come lexicographically after the * supplied value. * * This can be combined with limit to implement pagination by setting this to * the last table name from the previous page. */ startAfter?: string; /** An optional limit to the number of results to return. */ limit?: number; }它包含两个可选字段均与分页/裁剪相关字段类型语义startAfterstring仅返回按字典序lexicographical order排列在该值之后的表名。与limit组合可实现分页将上一页的最后一个表名作为下一页的startAfterlimitnumber可选的结果数量上限Connection.tableNames()的签名同样标注了deprecated见 nodejs/lancedb/connection.ts并明确说明Tables will be returned in lexicographical order表按字典序返回。同时支持两种调用形式tableNames(options?)—— 向后兼容的旧调用方式tableNames(namespacePath?, options?)—— 传入命名空间路径后再传分页选项。在实现层nodejs/lancedb/connection.tstableNames会先判断第一个参数是string[]命名空间路径还是普通对象选项再把startAfter与limit透传给底层inner.tableNames。旧接口的典型用法与分页模式TableNamesOptions的经典使用场景是取前 N 张表与按字典序游标翻页。仓库测试 nodejs/test/connection.test.ts 给出了最直接的可运行示例const db await connect(tmpDir.name); await db.createTable(b, [{ id: 1 }]); await db.createTable(a, [{ id: 1 }]); await db.createTable(c, [{ id: 1 }]); // 不带选项按字典序返回全部表名 let tables await db.tableNames(); expect(tables).toEqual([a, b, c]); // limit: 只返回前 1 张表 tables await db.tableNames({ limit: 1 }); expect(tables).toEqual([a]); // limit startAfter: 从 a 之后取 1 张表 tables await db.tableNames({ limit: 1, startAfter: a }); expect(tables).toEqual([b]); // 仅 startAfter: 取 a 之后的全部表 tables await db.tableNames({ startAfter: a }); expect(tables).toEqual([b, c]);由此可以总结出基于TableNamesOptions的手工分页套路每页读取limit条记录本页最后一个表名作为下一页的startAfter直到返回结果少于limit说明已到末尾。底层实现startAfter 与 limit 如何生效TableNamesOptions的两个字段最终会在 Rust 的 napi 绑定层被翻译为查询操作。见 nodejs/src/connection.rs#[napi(catch_unwind)] pub async fn table_names( self, namespace_path: OptionVecString, start_after: OptionString, limit: Optionu32, ) - napi::ResultVecString { let mut op self.get_inner()?.table_names(); op op.namespace(namespace_path.unwrap_or_default()); if let Some(start_after) start_after { op op.start_after(start_after); } if let Some(limit) limit { op op.limit(limit); } op.execute().await.default_error() }即startAfter映射为 Rust 侧的start_afterlimit映射为limit随后交由底层ListingDatabase执行。在 rust/lancedb/src/database/listing.rs 中可以看到字典序过滤与截断的具体逻辑——先按名称排序再跳过所有 start_after的条目最后按limit截断if let Some(start_after) request.start_after { // 定位第一个字典序大于 start_after 的位置 let position f.iter().position(|name| name.as_str() start_after.as_str()); // ... } if let Some(limit) request.limit { f.truncate(limit as usize); }这也解释了为什么startAfter被称为游标它本质上把上一页最后一条的字符串值当作一个字典序位置标记从而保证翻页时表名不会重复或遗漏前提是列表内容不发生变更。为什么弃用TableNamesOptions 的缺陷TableNamesOptions被标记为 Deprecated 并非因为它不能工作而是因为它的分页模型存在两个结构性弱点游标泄漏内部细节startAfter要求调用方理解字典序这一底层排序约定并自行维护最后一页最后一条表名的状态。表名的具体形态、排序规则一旦变化分页逻辑就会出错。无法表达继续翻页的通用语义对命名空间namespace数据库而言翻页需要的不只是名称游标而是一个能由服务端任意编码的续传标记。用表名当游标过于脆弱。因此 SDK 引入了全新的ListTablesOptionsConnection.listTables()方案见 nodejs/lancedb/connection.tsexport interface ListTablesOptions { /** * Token from a previous response, to resume listing where it left off. * * The token is opaque: it carries whatever the database needs to resume, and * callers should not construct or interpret one. */ pageToken?: string; /** * An upper bound on how many tables to return. * * A page may hold fewer than this and still not be the last one, so keep * going while the response carries a page token rather than while pages are * full. */ limit?: number; }对应的响应类型为 ListTablesResponse包含tables: string[]与可选的pageToken: string。新旧两代选项的对照关系能力TableNamesOptions已弃用ListTablesOptions推荐结果上限limit?: numberlimit?: number续传方式startAfter?: string字典序游标pageToken?: string不透明令牌翻页终止判定返回条数 limit响应中pageToken为undefined返回值Promisestring[]PromiseListTablesResponse含tables与pageToken官方文档对TableNamesOptions的弃用说明位于 docs/src/js/interfaces/TableNamesOptions.md指向的替代方案文档为 ListTablesOptions。迁移指南改用 listTables 与 pageTokenConnection.listTables的新签名见 nodejs/lancedb/connection.ts与tableNames保持了一致的重载结构支持listTables(options?)与listTables(namespacePath?, options?)两种形式。新版分页的核心要点源码 JSDoc 明确强调A page can be shorter thanlimitwithout being the last one, so walk until a response carries no page token —— 页面可能少于limit却并非最后一页因此必须以pageToken是否存在来判断是否翻页结束而不是看返回条数是否够limit。官方推荐的翻页循环写法const names []; let pageToken undefined; do { const page await conn.listTables({ pageToken, limit: 100 }); names.push(...page.tables); pageToken page.pageToken; } while (pageToken);逐步迁移对照迁移前旧 APIlet startAfter: string | undefined; for (;;) { const page await conn.tableNames({ limit: 100, startAfter }); names.push(...page); if (page.length 100) break; startAfter page[page.length - 1]; }迁移后新 APIlet pageToken: string | undefined; do { const page await conn.listTables({ limit: 100, pageToken }); names.push(...page.tables); pageToken page.pageToken; // undefined 即表示没有更多数据 } while (pageToken);测试用例验证仓库测试 nodejs/test/connection.test.ts 对listTables的分页行为做了完整验证const all await db.listTables(); expect(all.tables).toEqual([a, b, c]); expect(all.pageToken).toBeUndefined(); // 全部返回时没有令牌 const first await db.listTables({ limit: 1 }); expect(first.tables).toEqual([a]); expect(first.pageToken).toBeDefined(); // 还有剩余数据时有令牌 const second await db.listTables({ limit: 1, pageToken: first.pageToken, }); expect(second.tables).toEqual([b]);以及翻遍每一页且每张表恰好出现一次的断言const seen: string[] []; let pageToken: string | undefined undefined; do { const page: ListTablesResponse await db.listTables({ limit: 2, pageToken }); seen.push(...page.tables); pageToken page.pageToken; } while (pageToken); expect(seen).toEqual([a, b, c, d, e]);在 Rust 侧rust/lancedb/src/database/listing.rs 明确区分了两种游标注释指出 The page_token is opaque, unlike thestart_afterparameter ofSelf::table_names()并说明当没有更多结果时返回的page_token为Nonelimit是响应中表数量的上限但响应可能少于limit且仍有后续数据客户端应通过pageToken判断是否继续。同文件还包含一组针对分页边界的单元测试如 listing.rs 中的test_list_tables_pages_over_every_table_once、test_the_page_token_is_not_a_table_name、test_a_limit_the_listing_does_not_fill_leaves_no_token_behind进一步佐证了上述语义。使用建议与注意事项新代码一律使用listTablestableNames与TableNamesOptions已标注deprecated虽然出于向后兼容仍可用但不应在新代码中引入。以pageToken是否为空判断翻页终点旧接口中返回条数 limit即结束的判断在新接口下不成立——一页可能未填满但后面仍有数据务必按照响应无令牌才停止的模式编写循环。不要把pageToken当表名使用令牌是不透明的opaquecallers should not construct or interpret one不要尝试解析、拼接或持久化复用跨会话的令牌。命名空间支持listTables(namespacePath, options)与tableNames(namespacePath, options)均支持传入命名空间路径对于命名空间数据库listTables的底层请求会显式携带id根命名空间为空数组而非缺省见 nodejs/src/connection.rs 的注释测试 nodejs/test/connection.test.ts 演示了在子命名空间下列表的行为。limit为 0 的边界从 Rust 实现看limit Some(0)会直接返回空页且无令牌rust/lancedb/src/database/listing.rs调用时传入合理的正整数即可避免歧义。小结TableNamesOptions是 LanceDB Node.js SDK 早期基于字典序游标的表枚举方案其startAfterlimit组合在小规模、纯本地场景下足够直观但随着命名空间数据库与远端数据库的引入这种把底层排序细节暴露给调用方的分页模型不再适用。官方以ListTablesOptionsConnection.listTables()取代之用不透明的pageToken统一了分页语义。理解这一迁移脉络不仅能让你写出符合当前 SDK 规范的枚举代码也能更准确地把握 LanceDB 在列表 / 分页这类基础能力上的设计取舍。【免费下载链接】lancedbDeveloper-friendly OSS embedded retrieval library for multimodal AI. Search More; Manage Less.项目地址: https://gitcode.com/gh_mirrors/la/lancedb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考