2
\$\begingroup\$

I wrote a function to check if a nested object contains the key-value pair matched as parameter as following.

eq:
const obj ={
 "a":{
 "b":{
 "c1":["1","2"],
 "c2":"3"
 },
 "b2":"values",
 "b3": {"c5": "v"},
 },
 "a2":["v1","v2"],
 "a3":"v1"
}
checkNestedObjectByKeyValue(obj, "a3", "v1") // true
checkNestedObjectByKeyValue(obj, "a3", "v2") // false
checkNestedObjectByKeyValue(obj, "a2", ["v1","v2"]) // true
checkNestedObjectByKeyValue(obj, "a3", "v1") // true
checkNestedObjectByKeyValue(obj, "b3", {"c5": "v"}) // true
function checkNestedObjectByKeyValue(
 obj: Record<string, any>,
 objKey: string,
 objValue: string | Array<string>
): boolean {
 if (typeof obj !== 'object') return false;
 if (obj.hasOwnProperty(objKey)) {
 return JSON.stringify(obj[objKey]) === JSON.stringify(objValue)
 }
 for (const value of Object.values(obj)) {
 if (checkNestedObjectByKeyValue(value, objKey, objValue)) return true
 }
 return false
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jun 29, 2020 at 15:58
\$\endgroup\$
1
  • 1
    \$\begingroup\$ updated. code totally works \$\endgroup\$ Commented Jun 29, 2020 at 18:59

2 Answers 2

1
\$\begingroup\$

Based on your description of the function, I would expect this test to return true, but your implementation returns false. So, either your description is unclear, or your implementation is buggy.

const obj ={
 "a":{
 "b":{
 "a3":"v2",
 "c1":["1","2"],
 "c2":"3"
 },
 "b2":"values",
 "b3": {"c5": "v"},
 },
 "a2":["v1","v2"],
 "a3":"v1"
}
checkNestedObjectByKeyValue(obj, "a3", "v2") // false, but I would expect true
answered Jun 29, 2020 at 19:28
\$\endgroup\$
1
  • 1
    \$\begingroup\$ we have "a3": "v1" as first level that is why it return false. not sure how i can handle that \$\endgroup\$ Commented Jun 29, 2020 at 19:34
0
\$\begingroup\$

Main review

Your code works well in most cases, but the biggest change I recommend in order to skip over false positives would be to change the following lines

 if (obj.hasOwnProperty(objKey)) {
 return JSON.stringify(obj[objKey]) === JSON.stringify(objValue)
 }

to the following (move JSON.stringify(obj[objKey]) === JSON.stringify(objValue) into the conditional statement and return true):

 if (obj.hasOwnProperty(objKey) && JSON.stringify(obj[objKey]) === JSON.stringify(objValue)) {
 return true;
 }

As 200_success pointed out, your code returns false when a key exists in one part of the whole object but doesn't match and another key exists elsewhere which does match. This change will check whether a key matches first and proceeds to perform the recursive search for another key with matching value.

In the following code snippet, I changed the code to JavaScript so it could be run here in this post.

function checkNestedObjectByKeyValue(obj, objKey, objValue) {
 if (typeof obj !== "object") return false;
 if (obj.hasOwnProperty(objKey) && JSON.stringify(obj[objKey]) === JSON.stringify(objValue)) {
 return true;
 }
 for (const value of Object.values(obj)) {
 if (checkNestedObjectByKeyValue(value, objKey, objValue))
 return true;
 }
 return false;
}
const obj = {
 a: {
 b: {
 a3: "v2",
 c1: ["1", "2"],
 c2: "3"
 },
 b2: "values",
 b3: {
 c5: "v"
 },
 },
 a2: ["v1", "v2"],
 a3: "v1"
};
console.log(checkNestedObjectByKeyValue(obj, "a3", "v1"));
console.log(checkNestedObjectByKeyValue(obj, "a3", "v2"));
console.log(checkNestedObjectByKeyValue(obj, "a2", ["v1", "v2"]));
console.log(checkNestedObjectByKeyValue(obj, "b3", {
 c5: "v"
}));
// Added a check that should return false
console.log(checkNestedObjectByKeyValue(obj, "b2", "novalue"));

If the pattern of object properties is:

  • first level property name /^a\d*$/
  • second level property name /^b\d*$/
  • third level property name /^c\d*$/
  • etc.

Then this may not be necessary.

Other thoughts

When I first ran your code, I received an error: Argument of type '{ c5: string; }' is not assignable to parameter of type 'string | string[]'. which referenced the following line:

checkNestedObjectByKeyValue(obj, "b3", { c5: "v" })

I resolved this by adding | object to the objValue parameter as follows:

function checkNestedObjectByKeyValue(
 obj: Record<string, any>,
 objKey: string,
 objValue: string | Array<string> | object
): boolean {
answered Mar 16, 2022 at 17:49
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.