ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Sails.js 的 `.fetch()` 查询方法:让 Waterline 回传增删改记录的完整指南

Sails.js 的 `.fetch()` 查询方法:让 Waterline 回传增删改记录的完整指南 Sails.js 的.fetch()查询方法让 Waterline 回传增删改记录的完整指南【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails.fetch()是 Sails.js 内置 ORMWaterline中一个短小但极为实用的查询实例query instance方法。执行.create()、.createEach()、.update()或.destroy()这类写操作时默认情况下数据库不会回传受影响的记录链式调用.fetch()即可让 Waterline 与底层数据库适配器把这些记录原样返回。读完本文你将掌握.fetch()的用法、返回类型差异、与.meta({fetch: true})的关系以及在大批量写操作下如何规避性能陷阱。为什么需要.fetch()写操作的默认沉默行为在 Sails 应用中查询实例query instance是模型方法返回的可链式延迟对象Deferred例如Zookeeper.find()返回的对象在await之前并不会真正执行详见 Queries 文档。对于读操作.find()等执行后自然能拿到记录但对于写操作情况不同执行.update()、.create()、.createEach()或.destroy()时默认不会返回任何数据如果使用回调风格.exec()则回调的第二个参数将是undefined。这一设计是为了性能写操作默认只关心是否成功数据库无需把受影响的记录序列化回传。当你确实需要拿到刚刚写入/更新/删除的那条些记录时才需要链式调用.fetch()显式要求 Waterline 和底层数据库适配器把结果送回来。这一默认行为在框架源码中也有直接印证。在 lib/hooks/blueprints/actions/create.js 中blueprint 的 create action 执行完Model.create(data).meta(queryOptions.meta).exec(...)后会检查// If we didnt fetch the new instance, just return OK. if (!newInstance) { return res.ok(); }也就是说未启用 fetch 时即便通过 REST 接口调用 blueprint create响应也只是状态 OK而不携带新记录数据。基本用法零参数一行链式调用.fetch().fetch()不接受任何参数。它必须链式接在写操作模型方法返回的查询实例之后并且需要在查询真正执行await、.exec()、.then()或.toPromise()之前调用。典型示例创建后立即取回新记录原文档给出的经典示例是在.create()之后链式调用.fetch()从而立刻拿到带主键id的新记录var newUser await User.create({ fullName: Alice McBailey }).fetch(); sails.log(Hi, ${newUser.fullName}! Your id is ${newUser.id}.);执行await后newUser即为数据库中实际写入的那条记录包含自动生成的主键、默认值、生命周期回调写入的字段等。没有.fetch()的话newUser将是undefined。各写操作方法的返回类型与差异.fetch()在不同写操作方法上的返回形态不同理解这一点可以避免解包时的低级错误模型方法默认返回链式.fetch()后的返回.create()无单个记录((dictionary))即新建的那条记录.createEach()无记录数组((array))包含所有新建记录.update()无记录数组((array))包含所有被更新的记录.destroy()无记录数组((array))包含所有被删除的记录以 .create() 文档 中的 Result 表格说明为例为了优化性能创建出的记录默认不作为结果返回只有链式调用.fetch()后新记录才会被回传——并且要注意在部分适配器中这需要额外执行一次数据库查询。.update()与.destroy()的文档也做了同样说明。批量更新后取回所有受影响记录var updatedUsers await User.update({name:Finn}) .set({ name:Jake }) .fetch(); sails.log(Updated all ${updatedUsers.length} user${updatedUsers.length1?:s} named Finn to have the name Jake. Here they are now:); sails.log(updatedUsers);注意.update()的返回始终是数组——即使只有一条记录被更新。同时需注意update查询不支持skip/limit分页与select投影。删除后取回被销毁的记录var burnedBooks await Book.destroy({ controversiality: { : 0.9 } }).fetch(); sails.log(Deleted books:, burnedBooks);同样.destroy()返回被删除记录的数组。另请留意 .destroy() 文档 中的安全提示如果 criteria 传入空字典{}将销毁表中所有记录。新记录的主键是.fetch()最常见的用途.create()后拿不到主键是新手最常见的困惑之一。由于主键通常由数据库自动生成自增 id 或 uuid没有.fetch()就无法在后续逻辑中引用新记录。这也是.fetch()在 Sails 应用中出现频率最高的场景。底层原理.fetch()就是.meta({fetch: true})的快捷方式原文档明确给出了关键结论.fetch()只是.meta({fetch: true})的语法糖shortcut。.meta() 文档 的 Supported options 表格完整列出了fetch这一 meta 键OptionTypeDefaultDetailsfetch((boolean))false在执行.update()、.create()、.createEach()或.destroy()查询时设为true可让数据库适配器回传所有被更新/删除的记录否则.exec()回调的第二个参数为undefined。警告对影响大量记录的 update/destroy 查询启用该键可能引发性能问题。因此下面两种写法完全等价var newUser await User.create({ name: alice }).fetch(); // 等价写法 var newUser2 await User.create({ name: alice }).meta({ fetch: true });meta 键还有第三种设置途径在显式回调之后传入字典例如User.create({ name: alice }, function(err, newUser){/* ... */}, { fetch: true });从框架源码看fetch键贯穿了整个 blueprint 层。例如 lib/hooks/blueprints/parse-blueprint-options.js 在为 create action 组装查询选项时直接设置了queryOptions.meta { fetch: true }同一文件 L344-L345 对 update action 也做了同样处理。这说明REST 蓝图接口默认就能回传新建/更新后的记录随后还会在 create.js 中通过findOne做一次 populate 再返回。.fetch()与生命周期回调lifecycle callbacks的联动fetch键不仅影响返回值还影响模型生命周期回调的执行。在 lib/hooks/blueprints/actions/destroy.js 的源码注释中明确写道...well also include the meta query options for the purpose of enabling theafterDestroylifecycle callback (which only runs if.meta({fetch: true})is included).也就是说blueprint destroy action 之所以在findOne与destroy上都透传queryOptions.meta正是为了让afterDestroy这类生命周期回调在fetch: true时得以触发。由此可以推断当你需要依赖写操作后的生命周期回调如afterCreate、afterUpdate、afterDestroy时带上.fetch()或meta: {fetch: true}是必要条件之一反之若确认不需要回传数据省略它还能顺带跳过这些回调的额外开销。性能警告大批量写操作慎用.fetch()原文档给出了一条明确的警告Warning: This is not recommended for update/destroy queries that affect large numbers of records.原因在于要求适配器收集并回传每一条受影响记录的完整数据会显著增加数据库与 Node.js 进程之间的数据传输量部分适配器还需要额外发起一次查询见 .create() 文档 中 requires an extra database query in some adapters 的说明。在批量任务例如定时清理、批量状态迁移中这可能会拖慢整次操作。实践建议只需确认是否成功省略.fetch()仅关注是否抛错需要主键或受影响记录使用.fetch()但尽量缩小 criteria 的影响范围大表全量更新/删除考虑分批处理如按id分段避免单次查询影响海量记录追求性能且数据库支持把级联删除等需求下推到物理层如 MySQL/PostgreSQL 的 CASCADE 约束而不是依赖 ORM 层逐条处理详见 .meta() 文档 中关于cascade键的说明。错误处理与执行方式.fetch()本身不引入新的错误类型它与普通查询一样错误取决于所执行的模型方法与底层适配器UsageError、AdapterError、Error等详见各模型方法文档中的 Errors 小节。查询既可以用await执行推荐代码更简洁、更安全也可以用.exec()回调或.then()/.catch()链式执行。需要提醒的是.exec()回调风格下.fetch()决定的就是回调第二参数是否为undefined。小结.fetch()是 Waterline 查询实例中用一行代码换回写操作结果的便捷方法适用对象.create()、.createEach()、.update()、.destroy()返回值单个记录或记录数组取决于模型方法本质.meta({fetch: true})的快捷方式默认fetch: false附加价值与afterCreate/afterUpdate/afterDestroy等生命周期回调联动blueprint destroy 源码中有明确印证主要风险影响大量记录的 update/destroy 查询会带来性能开销应谨慎使用。在 fetch.md 原文档 基础上建议进一步阅读 Queries 总览 理解查询实例的 Deferred 机制以及 .meta() 了解cascade、skipAllLifecycleCallbacks、decrypt等更多 meta 键的完整能力。【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表