如何使用Mongoid History gem跟踪数组中的变更?
解决方案:封装变更提取逻辑为独立处理字段
我明白你的需求——不想把问题数组硬编码进脚本,同时只返回修改过的name或intro字段,而不是整个对象信息。核心思路是把变更字段提取逻辑封装成一个独立的处理单元(也就是你说的“创建一个字段”),下面给你具体实现方案:
1. 封装独立的变更提取函数
先写一个专门用来对比单个对象、提取name/intro变更的工具函数,完全和业务数据解耦:
// 专门提取name/intro变更的工具函数 const extractQuestionChanges = (originalItem, updatedItem) => { const changedFields = {}; // 对比name字段 if (originalItem.name !== updatedItem.name) { changedFields.name = updatedItem.name; } // 对比intro字段 if (originalItem.intro !== updatedItem.intro) { changedFields.intro = updatedItem.intro; } // 没有变更就返回null,方便后续过滤 return Object.keys(changedFields).length ? changedFields : null; };
2. 关联数据并生成结果数组
如果你的原始数组和修改后数组是通过id关联的(更健壮,不依赖数组顺序),可以用Map来快速匹配对应项,再批量处理:
// 示例原始问题数组(你可以从外部传入,不用嵌入脚本) const originalQuestions = [ { id: 1, name: "旧标题A", intro: "旧介绍A", otherField: "无关内容1" }, { id: 2, name: "旧标题B", intro: "旧介绍B", otherField: "无关内容2" } ]; // 示例修改后的数组(同样从外部传入) const updatedQuestions = [ { id: 1, name: "新标题A", intro: "旧介绍A", otherField: "无关内容1" }, { id: 2, name: "旧标题B", intro: "新介绍B", otherField: "无关内容2" } ]; // 把原始数组转成Map,用id做键,方便快速查找对应项 const originalMap = new Map(originalQuestions.map(item => [item.id, item])); // 生成只包含变更字段的结果数组 const changedQuestions = updatedQuestions.map(updatedItem => { const originalItem = originalMap.get(updatedItem.id); if (!originalItem) return null; // 处理新增的项,按需调整 // 调用之前封装的函数提取变更 const changes = extractQuestionChanges(originalItem, updatedItem); // 保留id用于标识是哪个问题的变更,不需要可以去掉 return changes ? { id: updatedItem.id, ...changes } : null; }).filter(item => item !== null); // 过滤掉没有变更的项 console.log(changedQuestions); // 输出结果: // [ // { id: 1, name: "新标题A" }, // { id: 2, intro: "新介绍B" } // ]
3. 进阶:把逻辑挂载为数组的自定义属性
如果你想把这个逻辑做成类似“字段”的形式,可以给数组原型添加一个不可枚举的方法,这样任何数组都能直接调用:
// 给数组添加自定义方法,作为专门的变更处理"字段" Object.defineProperty(Array.prototype, 'getQuestionChanges', { value: function(originalArray) { const originalMap = new Map(originalArray.map(item => [item.id, item])); return this.map(updatedItem => { const originalItem = originalMap.get(updatedItem.id); if (!originalItem) return null; const changedFields = {}; if (originalItem.name !== updatedItem.name) changedFields.name = updatedItem.name; if (originalItem.intro !== updatedItem.intro) changedFields.intro = updatedItem.intro; return Object.keys(changedFields).length ? { id: updatedItem.id, ...changedFields } : null; }).filter(Boolean); }, enumerable: false, // 避免遍历数组时显示这个方法 writable: true }); // 使用方式非常简洁,完全不用嵌入数据 const changedQuestions = updatedQuestions.getQuestionChanges(originalQuestions);
这样一来,你只需要从外部传入原始数组和修改后的数组,就能精准得到只包含name/intro变更的结果,完全符合你的需求。
内容的提问来源于stack exchange,提问作者C. Yee
相关产品推荐
相关产品推荐

