JavaScript recursive search in JSON object

后端 未结 6 490
野趣味
野趣味 2020-11-30 04:21

I am trying to return a specific node in a JSON object structure which looks like this

{
    \"id\":\"0\",
    \"children\":[
        {
            \"id\":\"         


        
6条回答
  •  悲&欢浪女
    2020-11-30 04:45

    Recursive structure search, modification, keys/values adjustments/replacement.

    Usage Example:

    const results = []; // to store the search results
    
    mapNodesRecursively(obj, ({ v, key, obj, isCircular }) => {
        // do something cool with "v" (or key, or obj)
        // return nothing (undefined) to keep the original value
    
        // if we search:
        if (key === 'name' && v === 'Roman'){
            results.push(obj);
        }
    
        // more example flow:
        if (isCircular) {
            delete obj[key]; // optionally - we decide to remove circular links
        } else if (v === 'Russia') {
            return 'RU';
        } else if (key.toLocaleLowerCase() === 'foo') {
            return 'BAR';
        } else if (key === 'bad_key') {
            delete obj[key];
            obj['good_key'] = v;
        } else {
            return v; // or undefined, same effect
        }
    });
    

    Tips and hints:

    You can use it as a search callback, just return nothing (won't affect anything) and pick values you need to your Array/Set/Map.

    Notice that callback is being run on every leaf/value/key (not just objects).

    Or you can use the callback to adjust particular values and even change keys. Also it automatically detects circular loops and provides a flag for you to decide how to handle them.

    The code

    (uses ES6)

    Function itself + some example demo data

    function mapNodesRecursively(obj, mapCallback, { wereSet } = {}) {
        if (!wereSet) {
            wereSet = new Set();
        }
    
        if (obj && (obj === Object(obj) || Array.isArray(obj))) {
            wereSet.add(obj);
    
            for (let key in obj) {
                if (!obj.hasOwnProperty(key)){
                    continue;
                }
    
                let v = obj[key];
    
                const isCircular = wereSet.has(v);
    
                const mapped = mapCallback({ v, key, obj, isCircular });
                if (typeof (mapped) !== 'undefined') {
                    obj[key] = mapped;
                    v = mapped;
                }
    
                if (!isCircular) {
                    mapNodesRecursively(v, mapCallback, { wereSet });
                }
            }
        }
    
        return obj;
    }
    
    let obj = {
        team: [
            {
                name: 'Roman',
                country: 'Russia',
                bad_key: 123,
            },
            {
                name: 'Igor',
                country: 'Ukraine',
                FOO: 'what?',
            },
            {
                someBool: true,
                country: 'Russia',
            },
            123,
            [
                1,
                {
                    country: 'Russia',
                    just: 'a nested thing',
                    a: [{
                        bad_key: [{
                            country: 'Russia',
                            foo: false,
                        }],
                    }],
                },
            ],
        ],
    };
    
    // output the initial data
    document.getElementById('jsInput').innerHTML = JSON.stringify(obj, null, 2);
    
    // adding some circular link (to fix with our callback)
    obj.team[1].loop = obj;
    
    mapNodesRecursively(obj, ({ v, key, obj, isCircular }) => {
        if (isCircular) {
            delete obj[key]; // optionally - we decide to remove circular links
        } else if (v === 'Russia') {
            return 'RU';
        } else if (key.toLocaleLowerCase() === 'foo') {
            return 'BAR';
        } else if (key === 'bad_key') {
            delete obj[key];
            obj['good_key'] = v;
        } else {
            return v;
        }
    });
    
    // output the result - processed object
    document.getElementById('jsOutput').innerHTML = JSON.stringify(obj, null, 2);
    .col {
      display: inline-block;
      width: 40%;
    }

    Recursive structure modification, keys/values adjustments/replacement

    1. Replacing "Russia" values with "RU"
    2. Setting the value "BAR" for keys "FOO"
    3. Changing the key "bad_key" to "good_key"

    BEFORE

    
      

    AFTER

    
      

提交回复
热议问题