【问题标题】:Find and update in nested json object在嵌套的 json 对象中查找和更新
【发布时间】:2013-08-01 08:34:08
【问题描述】:

我使用此代码从 sJhonny's Question 的 json 对象中找到所需的部分

数据样本

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

这样使用:

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

此代码是从源中选择匹配的一块。但我想要的是用新值更新源对象并检索更新后的源对象。

我想要类似的东西

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

我的代码

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

如果我给obj[key] = 'qwe';,这可行,但如果我将代码更改为obj[key] = newValue;,它会更新为未定义。

为什么会这样?

【问题讨论】:

  • in else if condition right?
  • 我不明白你想要做什么。您想在检索源对象的同时更新源对象吗? oO
  • 这段代码是从源中选择匹配的一块。但我想要的是用新值更新源对象并检索更新后的源对象
  • 好吧function(obj, key, newVal) { obj[key] = newVal; return obj; } 不过这有点没用...
  • 问题是它可以是一个嵌套的 json,所以我必须找到与此代码匹配的部分并使用 newValue 进行更新。我可能不知道要更新的值的确切位置,因为 json 是动态的。我拥有的是 id 和当前值(永远不会重复)

标签: javascript jquery json jquery-selectors


【解决方案1】:

你忘记在嵌套调用中传递 newValue

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

【讨论】:

    【解决方案2】:

    这个?

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

    【讨论】:

    • 不,是键值对不重复键可以多份
    【解决方案3】:
    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
    }
    

    这将使用 newValue (newVal) 对找到的值进行就地更新

    【讨论】:

    • 如果我要保存到嵌套 json 中的某些内容中,这将不起作用
    【解决方案4】:

    你可以试试我的解决方案

    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)
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      我尝试使用上面选择的解决方案,但它会使用相同的值更新每一行。因此,我添加了一种方法来定义您要更新的记录,以及一种在您已经循环过去后跟踪当前记录 ID 的方法。

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

      【讨论】:

        【解决方案6】:

        看看object-scan。我们现在将它用于大量数据处理。对我们来说,它使代码更易于维护,只需花一点时间就可以理解它。以下是您如何回答您的问题

        // 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/object-scan@13.8.0"></script>

        免责声明:我是object-scan的作者

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-04
          • 1970-01-01
          • 1970-01-01
          • 2016-07-27
          • 2021-01-10
          • 1970-01-01
          相关资源
          最近更新 更多