【问题标题】:JavaScript fill missing keys in one JSON object from another JSON objectJavaScript 从另一个 JSON 对象填充一个 JSON 对象中缺失的键
【发布时间】:2017-08-23 12:44:47
【问题描述】:

我有一个 JSON 对象 object1 需要从 object2 填充缺失的字段 - 不应替换现有字段。

我曾经使用过这个功能:

function fillObject(from, to) {
    for (var key in from) {
        if (from.hasOwnProperty(key)) {
            if (Object.prototype.toString.call(from[key]) === '[object Object]') {
                if (!to.hasOwnProperty(key)) {
                    to[key] = {};
                }
                fillObject(from[key], to[key]);
            }
            else if (!to.hasOwnProperty(key)) {
                to[key] = from[key];
            }
        }
    }
}

而且它一直有效,而两个对象具有相同的结构。现在 object1 中的 items 实际上可以出现在结构中的任何位置。 object1object2 的示例(结构可能看起来很有趣,因为我删除了所有不必要的键)。

var object1 = [
    {
        "position": 1,
        "items": [
            { 
                "position": 1, "itemId": 431
            },
            {
                "position": 2, "itemId": 1162, "title": "Overwritten title"
            }
        ]
    },
    {
        "position": 2,
        "groups": [
            {
                "position": 1
                "items": [
                    {
                        "position": 1, "itemId": 452, "title": "New title"
                    },
                    {
                        "position": 2, "itemId": 1388
                    },
                    {
                        "position": 3, "itemId": 1942
                    }
                ]
            },
            { 
                "position": 2, "itemId": 1942 
            },
            {
                "position": 3,
                "items": [
                    {
                        "position": 1, "itemId": 431
                    },
                    {
                        "position": 2, "itemId": 2000
                    },
                    {
                        "position": 3, "itemId": 452
                    }
                ]
            }
        ]
    },
    {
        "position": 3, "itemId": 1388
    },
    {
        "position": 4, "itemId": 2000, "title": "Extra title"
    }
];

var object2 [
    { "itemId": 431, "title": "Title 1" },
    { "itemId": 452, "title": "Title 2" },
    { "itemId": 1162, "title": "Title 3" },
    { "itemId": 1388, "title": "Title 4" },
    { "itemId": 1942, "title": "Title 5" },
    { "itemId": 2000 }
];

这就是我想要的结果:

var object1 = [
    {
        "position": 1,
        "items": [
            {
                "position": 1, "itemId": 431, "title": "Title 1"
            },
            {
                "position": 2, "itemId": 1162, "title": "Overwritten title"
            }
        ]
    },
    {
        "position": 2,
        "groups": [
            {
                "position": 1,
                "items": [
                    {
                        "position": 1, "itemId": 452, "title": "New title"
                    },
                    {
                        "position": 2, "itemId": 1388, "title": "Title 4"
                    },
                    {
                        "position": 3, "itemId": 1942, "title": "Title 5"
                    }
                ]
            },
            {
                "position": 2, "itemId": 1942, "title": "Title 5"
            },
            {
                "position": 3,
                "items": [
                    {
                        "position": 1, "itemId": 431, "title": "Title 1"
                    },
                    {
                        "position": 2, "itemId": 2000
                    },
                    {
                        "position": 3, "itemId": 452, "title": "Title 2"
                    },
                ]
            }
        ]
    },
    {
        "position": 3, "itemId": 1388, "title": "Title 4"
    },
    {
        "position": 4, "itemId": 2000, "title": "Extra title"
    }
];

提前感谢您的帮助。

【问题讨论】:

  • Object.assign()Spread syntax 如果您还不了解它们,可能会对您有所帮助。
  • 你能用itemId属性来唯一标识一个对象吗?

标签: javascript json


【解决方案1】:

如果您可以通过属性识别对象(例如 itemId),您可以执行以下操作

  • 将您的任务拆分为多个小子任务:复制缺失的属性、遍历对象结构、查找对象的对应来源
  • 将这些小块功能实现为函数并将它们一起使用。

const defaults = (target, src) => Object.keys(src)
  .forEach(key => key in target || (target[key] = src[key]))

const traverse = fn => traversable => {
  fn(traversable)
  
  const nested = Array.isArray(traversable) ? traversable : Object.values(traversable)  
  
  nested.filter(value => typeof value === 'object')
        .forEach(traverse(fn))
}

const fillById = id => sources => {
  const mapping = new Map(sources.map(item => [item[id], item]))
  
  return obj => {
    const src = mapping.get(obj.itemId)
    
    src && defaults(obj, src)
  }
}

var object1 = [
    {
        "position": 1,
        "items": [
            { 
                "position": 1, "itemId": 431
            },
            {
                "position": 2, "itemId": 1162, "title": "Overwritten title"
            }
        ]
    },
    {
        "position": 2,
        "groups": [
            {
                "position": 1,
                "items": [
                    {
                        "position": 1, "itemId": 452, "title": "New title"
                    },
                    {
                        "position": 2, "itemId": 1388
                    },
                    {
                        "position": 3, "itemId": 1942
                    }
                ]
            },
            { 
                "position": 2, "itemId": 1942 
            },
            {
                "position": 3,
                "items": [
                    {
                        "position": 1, "itemId": 431
                    },
                    {
                        "position": 2, "itemId": 2000
                    },
                    {
                        "position": 3, "itemId": 452
                    }
                ]
            }
        ]
    },
    {
        "position": 3, "itemId": 1388
    },
    {
        "position": 4, "itemId": 2000, "title": "Extra title"
    }
];

var object2 =  [
    { "itemId": 431, "title": "Title 1" },
    { "itemId": 452, "title": "Title 2" },
    { "itemId": 1162, "title": "Title 3" },
    { "itemId": 1388, "title": "Title 4" },
    { "itemId": 1942, "title": "Title 5" },
    { "itemId": 2000 }
];



traverse(fillById('itemId')(object2))(object1)

console.log(object1)

【讨论】:

  • 当我尝试运行您编写的内容时,mapping.get(obj.itemId); 出现 Uncaught RangeError: Maximum call stack size exceeded 错误。
  • 我的错,它来自我之前添加的另一段代码。
猜你喜欢
  • 1970-01-01
  • 2019-10-04
  • 2015-07-18
  • 2012-08-29
  • 2018-09-22
  • 2019-06-18
  • 1970-01-01
  • 2018-03-19
  • 2019-05-18
相关资源
最近更新 更多