12

I used this code to find the required portion from the json object from sJhonny's Question

Data Sample

TestObj = {
    "Categories": [{
        "Products": [{
            "id": "a01",
            "name": "Pine",
            "description": "Short description of pine."
        },
        {
            "id": "a02",
            "name": "Birch",
            "description": "Short description of birch."
        },
        {
            "id": "a03",
            "name": "Poplar",
            "description": "Short description of poplar."
        }],
        "id": "A",
        "title": "Cheap",
        "description": "Short description of category A."
    },
    {
        "Product": [{
            "id": "b01",
            "name": "Maple",
            "description": "Short description of maple."
        },
        {
            "id": "b02",
            "name": "Oak",
            "description": "Short description of oak."
        },
        {
            "id": "b03",
            "name": "Bamboo",
            "description": "Short description of bamboo."
        }],
        "id": "B",
        "title": "Moderate",
        "description": "Short description of category B."
    }]
};

Function to find

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

Use like so:

getObjects(TestObj, 'id', 'A'); // Returns an array of matching objects

This code is to select matching piece from the source. But what I want is to update the source object with new value and retrieve the updated source object.

I want something like

getObjects(TestObj, 'id', 'A', 'B'); // Returns source with updated value. (ie id:'A' updated to id:'B' in the returned object)

My code

function getObjects(obj, key, val, newVal) {
    var newValue = newVal;
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            obj[key] = 'qwe';
        }
    }
    return obj;
}

This works if i give obj[key] = 'qwe'; but if i change the code into obj[key] = newValue; its updated as undefined.

Why is that so?

6
  • in else if condition right? Commented Aug 1, 2013 at 8:41
  • I don't get what you want to do. Do you want to update the source object at the same time as you retrieve a piece of it ? oO Commented Aug 1, 2013 at 8:44
  • This code is to select matching piece from the source. But what I want is to update the source object with new value and retrieve the updated source object Commented Aug 1, 2013 at 8:47
  • Well then function(obj, key, newVal) { obj[key] = newVal; return obj; } That's kinda useless though... Commented Aug 1, 2013 at 8:51
  • The issue is that it can be a nested json so i have to find the matching piece with this code and update with the newValue. I may not know the exact position of the value to be updated since the json is dynamic. What i have with me is the id and the current value(which is never duplicated) Commented Aug 1, 2013 at 8:58

6 Answers 6

13

You forgot to pass newValue in the nested call

function getObjects(obj, key, val, newVal) {
    var newValue = newVal;
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val, newValue));
        } else if (i == key && obj[key] == val) {
            obj[key] = 'qwe';
        }
    }
    return obj;
}
Sign up to request clarification or add additional context in comments.

Comments

3

This ?

function update(obj, key, newVal) {
    for(var i in obj) {
        if(typeof obj[i] == 'object') {
            update(obj[i], key, newVal));
        } else if(i === key) {
            obj[i] = newVal;
        }
    }
    return obj;
}

1 Comment

No, It's the key value pair thats not duplicating key can be of multiple copies
2
function getObjects(obj, key, val, newVal) {
  for (var i in obj) {
      if (!obj.hasOwnProperty(i)) continue;
      if (i == key && obj[key] == val) {
          obj[key] = newVal;
      }
  }
  return obj
}

This will do the inplace update of a found value with the newValue (newVal)

1 Comment

This won't work if Im gonna save into something in a nested json
1

you can try my solution

const InsertOrUpdate = (dest, src) => {
    GetValue(dest, src, [])
}

const GetValue = (dest, src, keys) => {
    for (let key in src) {
        let srcValue = src[key]
        // Don't use push here
        // The concat() method does not change the existing arrays, but returns a new array, containing the values of the joined arrays
        let parentKeys = keys.concat(key)

        if (typeof (srcValue) === 'object') {
            GetValue(dest, srcValue, parentKeys)
        } else {
            SetValue(dest, parentKeys, srcValue)
        }
    }
}

const SetValue = (dest, keys, value) => {
    if (!keys.length || keys.length === 0) {
        return
    }

    let key = keys[0]
    let childKeys = keys.slice(1)

    // update
    // note: null is object
    if (dest[key] && typeof (dest[key]) === 'object') {
        SetValue(dest[key], childKeys, value)
    } else {
        // insert
        if (childKeys.length === 0) {
            dest[key] = value
        } else {
            // insert parent key & continue update
            dest[key] = {}
            SetValue(dest[key], childKeys, value)
        }
    }
}

Comments

0

I tried using the selected solution above, but it would update every row with the same value. So I added a way to define what record you want to update, and also a way to keep track of the current record ID once you've already looped past it.

function getObjects(obj, rowId, key, val, newVal, rId) {
    var objects = [];        
    for (var i in obj) {   
        if(obj[i].id !== undefined) rId = obj[i].id; 
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(this.updateObject(obj[i], rowId, key, val, newVal, rId));
        } else if (i == key && obj[key] == val) {
            if(rId == rowId) obj[key] = newVal;                      
        }
    }
    return obj;
}

Comments

0

Take a look at object-scan. We use it for a lot of data processing now. For us it makes the code much more maintainable, just takes a moment to wrap your head around it. Here is how you could answer your question

// const objectScan = require('object-scan');

const update = (data, needle, from, to) => objectScan([needle], {
  abort: true,
  rtn: 'bool',
  filterFn: ({ value, parent, property }) => {
    if (value === from) {
      parent[property] = to;
      return true;
    }
    return false;
  }
})(data);

// -------------------------------

const TestObj = { Categories: [{ Products: [{ id: 'a01', name: 'Pine', description: 'Short description of pine.' }, { id: 'a02', name: 'Birch', description: 'Short description of birch.' }, { id: 'a03', name: 'Poplar', description: 'Short description of poplar.' }], id: 'A', title: 'Cheap', description: 'Short description of category A.' }, { Product: [{ id: 'b01', name: 'Maple', description: 'Short description of maple.' }, { id: 'b02', name: 'Oak', description: 'Short description of oak.' }, { id: 'b03', name: 'Bamboo', description: 'Short description of bamboo.' }], id: 'B', title: 'Moderate', description: 'Short description of category B.' }] };

console.log(update(TestObj, '**.id', 'A', 'B'));
// => true
console.log(TestObj);
// => { Categories: [ { Products: [ { id: 'a01', name: 'Pine', description: 'Short description of pine.' }, { id: 'a02', name: 'Birch', description: 'Short description of birch.' }, { id: 'a03', name: 'Poplar', description: 'Short description of poplar.' } ], id: 'B', title: 'Cheap', description: 'Short description of category A.' }, { Product: [ { id: 'b01', name: 'Maple', description: 'Short description of maple.' }, { id: 'b02', name: 'Oak', description: 'Short description of oak.' }, { id: 'b03', name: 'Bamboo', description: 'Short description of bamboo.' } ], id: 'B', title: 'Moderate', description: 'Short description of category B.' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.