3

I have an object being returned that I don't know the structure of beforehand. The only thing I know is what values should be in the object. My goal isn't to check whether or not the returned object specifically matches another, but to check whether specific nested key-value pairs exist in the returned object.

The following is a random object that I could expect to be returned and the values that I want to check for. Is there anything out there already written that performs this type of check? Sorry for the lack of code, but I'm not sure where to really begin with this. I thought about maybe flattening the objects and doing a check, but due to unknown array lengths that idea didn't pan out.

// ob1 is the random object being returned. This will not be the same every time.
ob1 = {
    key_a: "val_a1",
    key_b: [
        "val_b1",
        "val_b2",
        "val_b3"
    ]
}

ob2a = {
    key_b: [
        "val_b2"
    ]
}

ob2b = {
    key_a: "val_a1",
    key_b: [
        "val_b3"
    ]
}

ob2c = {
    key_b: [
        "val_b2"
        "val_b3"
    ]
}

ob2d = {
    key_b: [
        "val_b1",
        "val_doesnt exist"
    ]
}

ob2e = {
    key_b: "val_b1"
}

checkExists(ob1,ob2a) // true
checkExists(ob1,ob2b) // true
checkExists(ob1,ob2c) // true
checkExists(ob1,ob2d) // false
checkExists(ob1,ob2e) // false
  • Loop through the entries in the test object with `Object.entries.every()`. For each of them, check if the property exists in the first object, and if so, whether the values match. – Barmar Jun 21 '21 at 19:12

2 Answers2

1

If I understood you correctly in your example ob1 is the object you want to compare each of the other ob2a, ..., ob2e.

This is what I came up with:

const checkExists = (ob1, ob2) => {
    // Filter for only matched keys between the two objects
    const matchedKeys = Object.keys(ob1).filter(key => {
        if(ob2[key] !== undefined) return key;
    });

    // No matched keys found so there are no nested key-value pairs 
    if(matchedKeys.length === 0) return false;
    else {
        let result = true;
        matchedKeys.forEach(key => {
            const ob1CurrentValue = ob1[key];
            const ob2CurrentValue = ob2[key];

            // Case: both values are arrays
            if(Array.isArray(ob1CurrentValue) && (Array.isArray(ob2CurrentValue))) {
                ob2CurrentValue.forEach(value => {
                    // If 1 value is not found result is false
                    if(!ob1CurrentValue.includes(value)) {
                        result = false;
                    }
                });
            // Case: both values are objects
            } else if(typeof ob1CurrentValue === 'object' && typeof ob2CurrentValue === 'object') {
                result = result && checkExists(ob1[key], ob2[key]);
            } else {
                result = ob1CurrentValue === ob2CurrentValue;
            }
        });

        return result;
    }
}

const ob1 = {key_a: "val_a1", key_b: ["val_b1", "val_b2", "val_b3"]};
const ob2a = {key_b: ["val_b2"]};
const ob2b = {key_a: "val_a1", key_b: ["val_b3"]};
const ob2c = {key_b: ["val_b2","val_b3"]};
const ob2d = {key_b: ["val_b1", "val_doesnt exist"]};
const ob2e = {key_b: "val_b1"};
const ob2f = {key_c: "val_c1"};
const ob2g = {key_c: "val_c1", key_b: "val_b1"};
const ob2h = {key_c: "val_b1", key_b: "val_b1"};
const ob2i = {key_a: "val_a1", key_b: ["val_b1", "val_b2", "val_b3"], key_c: { key_c1: ["val_c1_1"], key_c2: ["val_c2_1"]}};
const ob2j = {key_c: {key_c1: ["val_c1_1"]}};
const ob2k = {key_a: "val_a11"};
const objl = {key_a: "val_a11", key_c: {"key_c1":["val_c1_1"]}};

console.log(checkExists(ob1, ob2a)); // true
console.log(checkExists(ob1, ob2b)); // true
console.log(checkExists(ob1, ob2c)); // true
console.log(checkExists(ob1, ob2d)); // false
console.log(checkExists(ob1, ob2e)); // false
console.log(checkExists(ob1, ob2f)); // false
console.log(checkExists(ob1, ob2g)); // false
console.log(checkExists(ob1, ob2h)); // false
console.log(checkExists(ob2i, ob2j)); // true
console.log(checkExists(ob2i, ob2k)); // false
console.log(checkExists(ob2i, objl)); // false

What I did is first look for only matched keys between compared objects, if there are matched ones I check if ob1 contain all values of ob2 for each key.

Also I tried covering more cases like:

ob2f = {
    key_c: "val_c1"
}

ob2g = {
    key_c: "val_c1",
    key_b: "val_b1"
}

ob2h = {
    key_c: "val_b1",
    key_b: "val_b1"
}

I do not know if those are relevant for you.

Snirka
  • 602
  • 1
  • 5
  • 19
  • This doesn't work for nested key-value pairs. If ob1 is changed to '{"key_a":"val_a1","key_b":["val_b1","val_b2","val_b3"],"key_c":{"key_c1":["val_c1_1"],"key_c2":["val_c2_1"]}}' and you search for '{"key_c":{"key_c1":["val_c1_1"]}}' it'll fail. – Brad Bruggemann Jun 22 '21 at 14:45
  • 1
    I updated the code for those case too. – Snirka Jun 22 '21 at 17:44
  • '{"key_a":"val_a11","key_c":{"key_c1":["val_c1_1"]}}' passes, but should fail. I'll see if I can tinker with it. – Brad Bruggemann Jun 22 '21 at 19:52
  • 1
    I updated the code again check if it is good now for your cases. Something that was not clear to me in your problem is if ob1 and ob2 have the same key the value have to be the same type? – Snirka Jun 23 '21 at 14:34
  • 1
    Seems to work. And yes, same types, which seems to be how yours works. {key_c: {key_c1:"val_c1_1"}} failed and {key_c: {key_c1:["val_c1_1"]}} passed, which is how it should be. thanks for the help. Also, I don't know why this question was marked as a duplicate as it's not like the referenced already answered question at all. – Brad Bruggemann Jun 23 '21 at 19:17
0
    function checkIfExists(list1, list2) {
      let output = list2.filter(a=>!list1.some(b=>a==b))
      if(output.length==0) {
        return true;
      }
      return false
    }

   console.log(checkIfExists(ob1.key_b, ob2b.key_b))

You can add checks whether ob2b.key_b exists and is array or not. Please note that, as per your question, it will work only in case of array.

pride
  • 85
  • 1
  • 11
  • The solution seems unnecessarily complex. Here is a suggestion of a simplified version: `const checkIfExists = (list1, list2) => list2.every(a => list1.includes(a))` – CherryDT Jun 22 '21 at 17:41