Sails/Waterline `.destroyOne()` 详解:按条件精确删除单条记录并返回被删数据

发布时间:2026/9/21 1:46:12
Sails/Waterline `.destroyOne()` 详解:按条件精确删除单条记录并返回被删数据 Sails/Waterline.destroyOne()详解按条件精确删除单条记录并返回被删数据【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails导读.destroyOne()是 Sails 应用内 Waterline ORM 提供的模型方法之一用于在数据库中删除恰好匹配给定条件的一条记录若记录存在则永久删除并立即返回被删除的完整记录若不存在则返回undefined且不会误删多条数据。本篇围绕 docs/reference/waterline/models/destroyOne.md 展开结合 destroy 蓝图动作源码 与 destroy.md、archiveOne.md 等配套文档讲清其用法、返回值、错误处理、与.destroy()及.archiveOne()的取舍并给出可直接复制运行的实战示例。读完你将对单条删除场景下的 API 设计有完整认识并能正确地在自己的 Sails 动作action或 helper 中落地。一、方法概览一次调用最多删除一条.destroyOne()的调用方式非常简洁var destroyedRecord await Something.destroyOne(criteria);其中Something是模型名称例如User、Bookcriteria是用于匹配数据库记录的标准 Waterline 查询条件一个字典/普通对象。它与.destroy()最大的差异在于安全语义在真正执行数据库修改之前Waterline 会先检查给定 criteria 是否会匹配到多于一条记录如果会Waterline 将直接抛错UsageError而不会继续执行删除。也就是说.destroyOne()从设计上就杜绝了本想删一条、结果清空一片的事故——这一点与同为单条系列的.updateOne()、.archiveOne()完全一致。作为对照.destroy()则没有此保护见 destroy.md其文档明确警告如果你把空字典{}作为 criteria所有记录都会被删除且.destroy()查询不支持skip、limit分页与select投影。参数表参数类型说明1criteria((dictionary))用于在数据库中匹配记录的 Waterline 查询条件例如{id: 4}、{emailAddress: xexample.com}或带操作符的形式{score: {: 100}}返回值类型说明((dictionary?))由于.destroyOne()永远不会删除超过一条记录因此一旦有记录被删除它总是作为结果返回否则返回undefined错误与方法调用相关的错误可参考 Concepts Models and ORM Errors 中关于在 Sails 与 Waterline 中协商negotiate错误的说明。常见错误类型包括UsageErrorcriteria 非法或 criteria 会匹配到多条记录违反最多一条约束AdapterError底层数据库适配器出现问题数据库离线、权限不足等其他意外的Error。二、基础示例删除并判空官方文档给出的经典示例——按主键删除一本书并基于返回值做分支处理var burnedBook await User.destroyOne({id: 4}) if (burnedBook) { sails.log(Deleted book with id: 4.); } else { sails.log(The database does not have a book with id: 4.); }示例中User模型即代表书这一业务实体实际项目中请按你的模型替换。可以看到返回值本身就是天然的是否删除成功的信号返回了记录对象 → 删除确实发生了该对象即被删除记录的完整快照含全部属性值返回undefined→ 没有匹配到任何记录什么都没发生。这种返回值即结果的形态让代码无需先findOne()再destroy()两步操作避免了先查后删带来的竞态条件race condition风险。三、三种调用风格await / Promise / 回调与 Waterline 其他模型方法一样.destroyOne()是异步方法不能直接同步取用返回值。它支持三种写法详见 queries/exec.md 与 queries.md1.awaitSails v1 / Node.js v8推荐var removed await User.destroyOne({ emailAddress: troublemakerexample.com });2. Promise 链式调用User.destroyOne({ id: 42 }) .then((removed) { // removed 为被删记录或 undefined });3. 传统 Node 风格回调通过.exec()User.destroyOne({ id: 42 }) .exec((err, removed) { if (err) { return res.serverError(err); } // removed 为被删记录或 undefined });注意对于.destroyOne()这类方法调用时传入回调会直接执行不传回调则返回可链式组合的 Query 对象。请务必确保查询被真正执行await/.then()/.exec()否则删除不会发生。四、重要限制不支持.fetch()文档在 Notes 中明确强调因为它总是返回被删除的记录只要匹配到了所以此方法不支持.fetch()。这一点与.updateOne()相同却与.destroy()相反.destroy()出于性能考虑默认不返回被删记录部分适配器下返回被删记录还需要额外查询需要链式调用.fetch()或通过.meta({fetch: true})才会返回被删记录的数组.destroyOne()因为只删一条、且总是把结果交还给你.fetch()在此处既无必要也会被拒绝。因此删除一条并拿到被删数据就用.destroyOne()批量删除且不关心返回值或批量删除并想取回所有被删数据就用.destroy().fetch()。五、选择哪个删除方法destroy / destroyOne / archiveOne三者同属删除家族但语义差异明显决策时可以从删几条与要不要留底两个维度切入方法删除范围返回值是否留底适用场景.destroy()匹配条件的所有记录{}会清空全表默认不返回.fetch()后返回数组否批量清理、定时任务、确定要删干净的数据.destroyOne()本文恰好一条多条匹配时抛UsageError被删记录或undefined否按主键/唯一标识删除单个资源需要确认删除结果.archiveOne()恰好一条多条匹配时抛错归档记录或undefined是软删除到内置 Archive 模型合规留痕、可追溯删除但不需要程序化恢复archiveOne文档还给出了一个务实的建议如果你预计将来需要在应用里重新访问这些数据例如支持反删除功能与其用归档记录没有内置 unarchive 机制程序化处理更麻烦不如考虑在模型上加一个isDeleted布尔标志自行实现软删除。而.destroyOne()是永久且不可逆的删除——执行前请确认你的业务确实不再需要这条数据。六、源码视角.destroyOne()在蓝图中的落地实现虽然.destroyOne()本身是 Waterlinewaterline包本仓库之外提供的模型方法但 Sails 内置的 REST 蓝图接口DELETE /:model/:id正是单条删除语义的典型消费者其实现位于 lib/hooks/blueprints/actions/destroy.js可以反推出.destroyOne()的使用方式与设计动机。该动作的核心流程destroyOneRecord对应 Blueprint API Destroy通过parseBlueprintOptions(req)解析请求从 URL 中取出模型标识与主键值构造criteriacriteria[Model.primaryKey] queryOptions.criteria.where[Model.primaryKey]即按主键精确匹配单条先Model.findOne(criteria, populates)查出记录——源码注释说明之所以用两次查询而不是一条语句完成是为了给前端开发者提供更好的开箱即用体验能先返回 404 而不是吞掉错误若查不到记录返回404res.notFound(No record found with the specifiedid.)查到时再执行Model.destroy(criteria).meta(queryOptions.meta)并附带 meta 选项以触发afterDestroy生命周期回调该回调只有在.meta({fetch: true})时才会运行删除成功后若启用了pubsub钩子会调用Model._publishDestroy(...)通知订阅了该记录房间的 socket 客户端并向请求方res.ok(record)返回被删记录含 populate 出来的关联数据如 Destroy.md 所示socket 通知的previous字段即被删记录的完整属性字典。从中可以看到与本文主题一致的三个要点单条删除的 HTTP 语义DELETE /user/4与.destroyOne()的最多一条语义同源被删记录会被完整返回REST 响应体与.destroyOne()的返回值一致先查后删的流程恰恰解释了为什么.destroyOne()总是能免费给出被删记录——不必像.destroy()那样为了取回数据额外付出一次数据库查询。七、实战在 Sails 动作中安全使用.destroyOne()把.destroyOne()用到真实动作里推荐配合 .intercept() / .tolerate() 做细粒度错误协商参考 errors.md 的完整范例。下面的动作示例演示了删除指定 id 的宠物找不到则返回 404的完整写法module.exports { friendlyName: Delete pet, description: Permanently destroy the pet with the specified id., inputs: { id: { type: number, required: true } }, exits: { notFound: { responseType: notFound }, success: { description: Pet destroyed. } }, fn: async function ({ id }) { var destroyedPet await Pet.destroyOne({ id }) .intercept(UsageError, (err) { // 例如 criteria 非法、或匹配到多条记录 return err; }); if (!destroyedPet) { throw notFound; } return { pet: destroyedPet }; } };要点回顾criteria 使用主键{id}时天然满足单条约束是最稳妥的用法若用其他字段如{firstName:Finn}务必确认业务上该字段唯一否则 Waterline 会在删除前抛UsageError而这正是.destroyOne()的保护价值所在返回值undefined即无记录可删可直接映射为 404 等业务响应由于.destroyOne()不支持.fetch()不要再链式调用.fetch()。八、关联阅读方法总览与内置模型方法清单Working with models批量删除含{}清空警告、.fetch()与 meta 键说明.destroy()软删除对照.archiveOne()单条更新的姊妹方法.updateOne()查询条件语法Waterline Query Language错误分类与协商Concepts Models and ORM ErrorsREST 层面的单条删除接口含 socket 通知结构Blueprint API Destroy蓝图实现源码lib/hooks/blueprints/actions/destroy.js结语.destroyOne()的价值在于把安全删除单条 返回被删数据封装成一个方法多条匹配直接抛错、未匹配返回undefined、匹配则完整返回记录配合await和.intercept()可以写出既简洁又稳健的删除逻辑。选择删除方案时只需记住一句口诀——确认单条、需要结果、永久删除用.destroyOne()批量处理用.destroy()需要留底用.archiveOne()。【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考