【问题标题】:Get parent and grandparent keys from a value inside a deep nested object [closed]从深层嵌套对象中的值获取父键和祖父键 [关闭]
【发布时间】:2019-08-29 13:19:13
【问题描述】:

我有一个深度嵌套的 JavaScript 对象,我知道一个值位于对象的最低位置。我想知道父键和祖父键。

我设置了一个jsbin https://jsbin.com/yimugezuxe/edit?js,console

基于值“uniqueID#9aserdf”,我想知道/返回其父键:来自下面对象的“Stage 2”和“Level 2”:

const obj = {
    "Level 1": {
        "Stage 1": [
        {
            "title": "Parent 1",
            "id": "Parent1#id",
            "Children": [
            {
                "title": "Steve",
                "id": "uniqueID1"
            },
            {
                "title": "James",
                "id": "uniqueID#9"
            }
            ]
        }
        ]
    },
    "Level 2": {
        "Stage 1": [
        {
            "title": "Parent 4",
            "id": "Parent4#id",
            "Children": [
            {
                "title": "Tim",
                "id": "uniqueIDadsf"
            },
            {
                "title": "Hans",
                "id": "uniqueID#9asdf"
            }
            ]
        }
        ],
        "Stage 2": [
        {
            "title": "Parent 10",
            "id": "Parent10#id",
            "Children": [
            {
                "title": "Chris",
                "id": "uniqueIDadsf33"
            },
            {
                "title": "Jack",
                "id": "uniqueID#9aserdf"
            }
            ]
        }
        ]
    }
};

// based on the value 'uniqueID#9aserdf' I want to know/return its parent keys: 'Stage 2' and 'Level 2'

【问题讨论】:

标签: javascript json object


【解决方案1】:

试试这个代码:

它使用递归并提供父节点。

const obj = {
    "Level 1": {
        "Stage 1": [{
            "title": "Parent 1",
            "id": "Parent1#id",
            "Children": [{
                    "title": "Steve",
                    "id": "uniqueID1"
                },
                {
                    "title": "James",
                    "id": "uniqueID#9"
                }
            ]
        }]
    },
    "Level 2": {
        "Stage 1": [{
            "title": "Parent 4",
            "id": "Parent4#id",
            "Children": [{
                    "title": "Tim",
                    "id": "uniqueIDadsf"
                },
                {
                    "title": "Hans",
                    "id": "uniqueID#9asdf"
                }
            ]
        }],
        "Stage 2": [{
            "title": "Parent 10",
            "id": "Parent10#id",
            "Children": [{
                    "title": "Chris",
                    "id": "uniqueIDadsf33"
                },
                {
                    "title": "Jack",
                    "id": "uniqueID#9aserdf"
                }
            ]
        }]
    }
};

let path = [];


function getParentAndGrandParent(path, json, value) {

    for (var key in json) {

        if (typeof json[key] === 'object') {
            path.push(key.toString());
            // console.log("PAth : " + path)
            getParentAndGrandParent(path, json[key], value);
            path.pop();
        } else {
            if (json[key] == value) {
                console.log("Parent : " + path);
            }
        }
    }

}

getParentAndGrandParent(path, obj, 'uniqueID#9asdf')

【讨论】:

  • 这很优雅,但是,如果我尝试返回语句,它会以某种方式未定义:所以不是:console.log("Parent : " + path); 我这样做了:return path;
  • @Kalaschnik 可以尝试创建一个 promise 并从中解析值,例如:resolve(path)
【解决方案2】:

类似这样的:

for (var prop in obj) {
  for (var prop2 in obj[prop]) {

  }
}

然后用这个方法向下迭代检查

这是一个完整的例子:

for (var prop in obj) {
  for (var prop2 in obj[prop]) {
    //console.log(prop2);
    for (var prop3 in obj[prop][prop2]) {
      //console.log("->"+prop3);
      for (var prop4 in obj[prop][prop2][prop3]) {
        //console.log("->"+"->"+prop4);
        for (var prop5 in obj[prop][prop2][prop3][prop4]) {
          //console.log("->"+"->"+"->"+prop5);
          for (var prop6 in obj[prop][prop2][prop3][prop4][prop5]) {
            //console.log("->"+"->"+"->"+"->"+prop6);
            if (obj[prop][prop2][prop3][prop4][prop5][prop6] == "uniqueID#9aserdf") {
              console.log("Stage :" +prop2 + " == Level :" + prop);
            }
          }
        }
      }
    }
  }
}

您可以去掉代码中的 cmets,以帮助查看您在对象中的位置。

【讨论】:

  • 好吧,我想的是嵌套循环。然而我认为有更优雅的方法可以解决这个问题(又名功能性)?
  • 不能再往下走...for (let level in obj) { for (let stage in obj[level]) { console.log(stage) } }
【解决方案3】:

这里是一个函数,它返回一个包含 Level 和 Stage 的元组,如果没有匹配的 ChildrenId,则返回 [null, null]。

这有点乱,但我还没有找到简单的方法。

const findAncestors = (obj, ChildrenId) => {

    let stageResult = null;

    const result = Object.entries(obj).find(level => {
        const validLevel = Object.values(level[1]).find((stage, index) => {
            const validId = stage[0].Children.some(children => {
                return children.id === ChildrenId
            })
            if (validId) {
                stageResult = Object.keys(level[1])[index];
            }
            return validId;
        })
        return validLevel != undefined;
    })

    return stageResult === null ? [null, null] : [result[0], stageResult];
}

【讨论】:

    【解决方案4】:

    我将 getObject 从 this answer 修改为 Zach 到 Find by key deep in a nested object 以接受属性名称和值。

    我将findPath直接从this answer通过ibrahim mahrir拉到Javascript - Find path to object reference in nested object。

    结合它们,您可以获得包含您正在寻找的属性的对象,然后使用它来获取该对象的路径。您可以更改 findPath 以返回一个字符串数组,如果您想要的话,只提取前两个。

    function getObject(theObject, propName, propValue) {
        var result = null;
        if(theObject instanceof Array) {
            for(var i = 0; i < theObject.length; i++) {
                result = getObject(theObject[i], propName, propValue);
                if (result) {
                    break;
                }   
            }
        }
        else
        {
            for(var prop in theObject) {
                //console.log(prop + ': ' + theObject[prop]);
                if(prop == propName) {
                    if(theObject[prop] == propValue) {
                        return theObject;
                    }
                }
                if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
                    result = getObject(theObject[prop], propName, propValue);
                    if (result) {
                        break;
                    }
                } 
            }
        }
        return result;
    }
    
    function findPath(a, obj) {
        for(var key in obj) {                                         // for each key in the object obj
            if(obj.hasOwnProperty(key)) {                             // if it's an owned key
                if(a === obj[key]) return key;                        // if the item beign searched is at this key then return this key as the path
                else if(obj[key] && typeof obj[key] === "object") {   // otherwise if the item at this key is also an object
                    var path = findPath(a, obj[key]);                 // search for the item a in that object
                    if(path) return key + "." + path;                 // if found then the path is this key followed by the result of the search
                }
            }
        }
    }
    
    const data = {
        "Level 1": {
            "Stage 1": [
            {
                "title": "Parent 1",
                "id": "Parent1#id",
                "Children": [
                {
                    "title": "Steve",
                    "id": "uniqueID1"
                },
                {
                    "title": "James",
                    "id": "uniqueID#9"
                }
                ]
            }
            ]
        },
        "Level 2": {
            "Stage 1": [
            {
                "title": "Parent 4",
                "id": "Parent4#id",
                "Children": [
                {
                    "title": "Tim",
                    "id": "uniqueIDadsf"
                },
                {
                    "title": "Hans",
                    "id": "uniqueID#9asdf"
                }
                ]
            }
            ],
            "Stage 2": [
            {
                "title": "Parent 10",
                "id": "Parent10#id",
                "Children": [
                {
                    "title": "Chris",
                    "id": "uniqueIDadsf33"
                },
                {
                    "title": "Jack",
                    "id": "uniqueID#9aserdf"
                }
                ]
            }
            ]
        }
    };
    const o = getObject(data, "id", "uniqueID#9aserdf");
    console.log(o);
    const path = findPath(o, data);
    console.log(path);

    【讨论】:

      猜你喜欢
      • 2021-10-22
      • 2013-02-19
      • 1970-01-01
      • 2014-04-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      • 2012-11-12
      • 2021-02-20
      相关资源
      最近更新 更多