简体   繁体   中英

JavaScript fill missing keys in one JSON object from another JSON object

I have a JSON object object1 that needs to have missing fields filled from object2 - existing fields should not be replaced.

I used to use this function:

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];
            }
        }
    }
}

And it worked all the while both objects had the same structure. Now the items inside object1 can actually appear anywhere in the structure. Example of object1 and object2 (structure might seem funny as I've removed all the unnecessary keys).

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 }
];

And this is what I want the result to be:

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"
    }
];

Thanks in advance for the help.

Provided that you could identify object by a property (say itemId ) you could do the following

  • Split your task into small subtasks: copy missing property, traverse object structure, find corresponding source for an object
  • Implement those small chunks of functionality as functions and use them together.

 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) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM