 与 allDocs() 全解析)
数据库数据同步【免费下载链接】pouchdb:kangaroo: - PouchDB is a pocket-sized database.项目地址https://gitcode.com/gh_mirrors/po/pouchdb点击查看免费下载get()、put()、remove()让我们能够操作单个文档但一个数据库的价值恰恰在于能一次处理大量操作。PouchDB 为此提供了两个批量操作 API用于批量写入的bulkDocs()和用于批量读取的allDocs()。本篇指南以 docs/guides/bulk-operations.md 为骨架结合源码与测试带你掌握批量写入的正确姿势、利用_id排序的allDocs()高效查询技巧以及为何 99% 的应用都可以用allDocs()替代慢速query()这一核心经验。用bulkDocs()批量写入文档bulkDocs()的 API 非常简单它接受一个你想put()进数据库的文档数组db.bulkDocs([ { _id: mittens, occupation: kitten, cuteness: 9.0 }, { _id: katie, occupation: kitten, cuteness: 7.0 }, { _id: felix, occupation: kitten, cuteness: 8.0 } ]);这段代码等价于逐个调用put()db.put({ _id: mittens, occupation: kitten, cuteness: 9.0 }).then(function () { return db.put({ _id: katie, occupation: kitten, cuteness: 7.0 }); }).then(function () { return db.put({ _id: felix, occupation: kitten, cuteness: 8.0 }); });从 batch_create API 文档 可以看到bulkDocs()的完整签名是db.bulkDocs(docs, [options], [callback])docs参数即文档数组。API 文档同时给出了回调、async/await与 Promise 三种风格// Promise 风格 db.bulkDocs([ {title : Lisa Says, _id: doc1}, {title : Space Oddity, _id: doc2} ]).then(function (result) { // handle result }).catch(function (err) { console.log(err); });省略_id让数据库自动生成如果数组中某个文档省略了_id参数数据库会为该文档创建新的 ID// 自动生成 _id db.bulkDocs([ {title : Lisa Says}, {title : Space Oddity} ]).then(function (result) { // handle result });批量更新与删除_rev与_deleted的规则你同样可以用bulkDocs()一次性更新或删除多个文档。每条文档的规则与put()完全一致更新时必须同时携带_id和_rev_rev必须与更新所基于的文档修订一致删除时则带上值为true的_deleted// 批量更新携带 _rev db.bulkDocs([ { title : Lisa Says, artist : Velvet Underground, _id : doc1, _rev : 1-84abc2a942007bee7cf55007cba56198 }, { title : Space Oddity, artist : David Bowie, _id : doc2, _rev : 1-7b80fc50b6af7a905f368670429a757e } ]).then(function (result) { // handle result }); // 批量删除_deleted: true db.bulkDocs([ { title : Lisa Says, _deleted : true, _id : doc1, _rev : 1-84abc2a942007bee7cf55007cba56198 }, { title : Space Oddity, _deleted : true, _id : doc2, _rev : 1-7b80fc50b6af7a905f368670429a757e } ]).then(function (result) { // handle result });关于_rev与_deleted的详细语义可以回看 docs/guides/updating-deleting.md 指南。响应结构逐条返回ok/id/revbulkDocs()的响应是一个数组每个元素对应你传入数组中的同序文档[ { ok: true, id: doc1, rev: 1-84abc2a942007bee7cf55007cba56198 }, { ok: true, id: doc2, rev: 1-7b80fc50b6af7a905f368670429a757e } ]如果某个文档出错错误会以独立元素返回与成功元素混在一起[ { status: 409, name: conflict, message: Document update conflict, error: true } ]这意味着你必须逐条检查返回数组而不能假设整体成功或整体失败。进阶选项new_edits: false在 options 对象上设置new_edits: false时你可以写入来自其他数据库的既有文档而不会为它们分配新的修订 ID。通常只有复制replication算法才需要这样做。在 PouchDB 源码中new_edits默认被设为true且当new_edits为false时会按_id_rev排序文档见 #2935 相关修复并只返回错误项与 CouchDB 行为一致。为什么批量操作更快批量操作通常比逐个操作更快因为它们可以被合并为本地 IndexedDB/WebSQL合并为单个事务transaction远程 CouchDB合并为单个 HTTP 请求。从源码看PouchDB 核心层packages/node_modules/pouchdb-core/src/adapter.js对bulkDocs做了统一的入参校验要求req.docs必须是数组否则报MISSING_BULK_DOCS每个元素必须是对象NOT_AN_OBJECT_rev必须合法INVALID_REV并检查附件名称与content_type。校验通过后再委托给具体适配器IndexedDB、WebSQL、LevelDB 或 HTTP的_bulkDocs实现——这也解释了为什么批量写入能在不同后端获得一致的行为与性能收益。重要警告批量操作不是事务bulkDocs()与allDocs()都不是传统意义上的事务。如果其中某个put()失败你不应假设其他操作也会失败。PouchDB 官方警告强调CouchDB 和 PouchDB 设计上不支持事务文档document是最小的原子操作单元。这是分布式数据库在离线优先offline-first场景下的刻意取舍——在复制冲突面前事务无法跨节点保持。因此设计批量写入逻辑时请务必为部分成功做好幂等处理与错误重试策略。用allDocs()批量读取文档allDocs()让你一次读取大量文档其完整签名为db.allDocs([options], [callback])。最关键的特性是allDocs()返回的文档按_id的字典序lexicographic order排序。这让_id成为一个非常强大的字段——它不仅可以唯一标识文档还能决定文档的排序方式。例如前面示例中的小猫们之所以按名字排序正是因为它们的名字被用作_id。用日期作_id天然按时间排序一个常见的技巧是使用new Date().toJSON()作为_id。这样你的所有文档都会自动按日期排序。例如保存三只不同日期的小猫再按日期取回db.put({ _id: new Date().toJSON(), name: Mittens, occupation: kitten, cuteness: 9.0 }).then(function () { return db.put({ _id: new Date().toJSON(), name: Katie, occupation: kitten, cuteness: 7.0 }); }).then(function () { return db.put({ _id: new Date().toJSON(), name: Felix, occupation: kitten, cuteness: 8.0 }); }).then(function () { return db.allDocs({include_docs: true}); }).then(function (response) { console.log(response); }).catch(function (err) { console.log(err); });由于_id是字典序排序而 ISO 8601 格式的new Date().toJSON()如2026-09-20T03:55:51.123Z恰好按时间先后排列取回的文档自然就按写入时间排序了。响应结构allDocs()的典型响应如下{ offset: 0, total_rows: 1, rows: [{ doc: { _id: 0B3358C1-BA4B-4186-8795-9024203EB7DD, _rev: 1-5782E71F1E4BF698FA3793D9D5A96393, title: Sound and Vision, _attachments: { attachment/its-id: { content_type: image/jpg, data: R0lGODlhAQABAIAAAP7//wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw, digest: md5-57e396baedfe1a034590339082b9abce } } }, id: 0B3358C1-BA4B-4186-8795-9024203EB7DD, key: 0B3358C1-BA4B-4186-8795-9024203EB7DD, value: { rev: 1-5782E71F1E4BF698FA3793D9D5A96393 } }] }响应中主要有三部分total_rows数据库中未删除文档的总数offset传入的skip值在 CouchDB 中则是实际偏移量rows文档行数组——如果你没有设置include_docs: true每行只含_id/_rev而不含完整文档。此外如果设置了update_seq: true响应中还会包含update_seq字段。allDocs()选项全解根据 batch_fetch API 文档所有选项默认均为false除非另有说明。常用选项如下选项说明include_docs在每行的doc字段中包含文档本体否则默认只返回_id和_revconflicts在文档的_conflicts字段中包含冲突信息attachments以 base64 字符串形式包含附件数据binary以 Blob/Buffer 形式返回附件数据替代 base64 字符串startkey/endkey只获取_id位于某一范围两端包含内的文档inclusive_end是否包含_id恰好等于endkey的文档默认truelimit最多返回的文档数skip跳过前 N 个文档警告在 IndexedDB/LevelDB 上性能较差descending反转输出顺序注意descending: true时startkey与endkey的顺序也要反转key只返回_id恰好等于该字符串键的文档keys一次性获取多个字符串键的文档见下方详细规则update_seq返回update_seq值指示视图所反映的底层数据库序列号keys选项的详细规则keys与startkey/endkey互斥不能同时指定返回的rows与传入的keys数组顺序一致已删除文档的行会包含删除操作的修订 ID并在value中额外带有deleted: true不存在的文档行只包含error: not_found属性。范围查询startkey/endkey利用startkey与endkey可以一次性取出_id落在某个区间内的所有文档db.allDocs({ include_docs: true, attachments: true, startkey: bar, endkey: quux }).then(function (result) { // handle result });这会返回所有_id介于bar与quux之间的文档两端包含。前缀搜索\ufff0技巧你还可以用allDocs()做前缀搜索——例如找出所有_id以foo开头的文档——方法是利用特殊的高位 Unicode 字符\ufff0db.allDocs({ include_docs: true, attachments: true, startkey: foo, endkey: foo\ufff0 }).then(function (result) { // handle result });这之所以有效是因为 CouchDB/PouchDB 的_id按字典序排序而\ufff0是 Unicode 中一个极高的码位位于所有普通字符包括中文、emoji 等之后因此foo\ufff0恰好是以 foo 开头这一前缀区间的上界。请用allDocs()真的allDocs()是 PouchDB 世界里被低估的明星 API。它不仅按顺序返回文档还支持反转顺序descending按_id过滤key/keys在_id上做大于/小于切片startkey/endkey、inclusive_end、limit、skip。太多开发者误解并忽视了这一 API。当有人说我的 PouchDB 应用好慢时通常是因为他们用了慢速的query()API而本应使用快速的allDocs()API。要高效使用allDocs()强烈推荐阅读 “Pagination strategies with PouchDB” 一文。对于99% 的应用你需要的分页、排序、搜索功能都可以用allDocs()完成。关于分页API 文档还给出了一条性能忠告虽然limit与skip也可用于分页但存在与 CouchDB 相同的性能问题尤其是skip在 IndexedDB/LevelDB 上需要遍历跳过性能较差更推荐使用startkey/endkey的游标模式。源码视角bulkDocs与allDocs的内部实现PouchDB 的核心层位于 packages/node_modules/pouchdb-core/src/adapter.js其中对两个批量 API 做了统一的入口校验bulkDocsL774-L861兼容Array与{docs: [...]}两种入参形式校验docs必须是数组MISSING_BULK_DOCS、每项必须是对象NOT_AN_OBJECT、_rev必须合法INVALID_REV校验附件名称合法性并对缺少content_type的附件给出警告处理new_edits默认true为false时按_id/_rev排序文档以正确处理同一文档的连续修订并过滤出仅含错误的结果最后委托给各适配器的_bulkDocs实现并为本地适配器的错误/冲突结果补上id字段。allDocsL713-L749默认skip 0并兼容start_key/end_key下划线别名当指定keys时校验其必须是数组且不能与startkey/endkey/key同时使用否则报QUERY_PARSE_ERROR本地数据库下keys为空数组时直接以limit: 0短路返回最终调用适配器的_allDocs完成按_id索引的读取。这些逻辑与本文介绍的 API 行为一一对应是理解为什么allDocs()快、skip慢、keys返回顺序保持传入顺序等细节的权威依据。测试佐证批量操作的行为约束仓库的集成测试对上述语义做了完整验证tests/integration/test.bulk_docs.js 覆盖了空 bulkDocs、new_editsfalse的多种场景如 #2935、连续修订、批量更新后删除再冲突、_local文档的批量删除以及错误返回中id字段的补全#6039tests/integration/test.all_docs.js 覆盖了keys含与skip/limit组合、非法keys、start_key/end_key别名#3883、total_rows与skip/limit的组合、转义后的startkey/endkey、inclusive_endfalse、descending与startkey/endkey反转、Unicode_id排序以及update_seq#6230等边界情况。相关 API 文档与下一步批量操作的完整参数细节可查阅bulkDocs() 批量创建/更新/删除文档 API 文档对应模板 docs/_includes/api/batch_create.htmlallDocs() 批量读取文档 API 文档对应模板 docs/_includes/api/batch_fetch.html现在你已经牢牢掌握了bulkDocs()与allDocs()这两个批量操作利器。下一步可以继续阅读 attachments 附件指南学习如何在文档中存储文件与二进制数据。赞分享数据库数据同步【免费下载链接】pouchdb:kangaroo: - PouchDB is a pocket-sized database.项目地址https://gitcode.com/gh_mirrors/po/pouchdb点击查看免费下载相关推荐PouchDB性能优化批量操作与数据压缩技术终极指南PouchDB性能优化批量操作与数据压缩技术终极指南 PouchDB是一个轻量级的JavaScript数据库专为Web和移动应用设计提供出色的离线数据同步数据库数据同步EVM Opcodes安全指南避免智能合约漏洞的10个关键操作码EVM Opcodes安全指南避免智能合约漏洞的10个关键操作码 想要构建安全的以太坊智能合约吗了解EVM操作码是每个开发者的必备技能本文将为您揭示10个数据库数据同步GORM批量操作指南Batch Insert与FindInBatches实战GORM批量操作指南Batch Insert与FindInBatches实战 想要高效处理海量数据GORM的批量操作功能是你的最佳选择 本文将详细介绍后端数据库ORM上一篇Spin安全最佳实践保障WebAssembly应用安全性的完整方案下一篇Raspberry Pi USB Bootrpiboot未来展望新功能路线图与社区贡献指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考