You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:19:07