Search code examples
javascriptarraysjestjscomparisonjavascript-objects

Check if all the key/value paris of a nested object are present in an array of objects


I have some data in the following format:

const data = [
    {
        "region": "London",
        "code": "0",
        "airport": "Heathrow",
        "messages": [
            {
                "date": 1617063225,
                "region": "London",
                "message": "This is a test message"
            }
        ]
    },
    ... // 300 more objects in the same format
]

I would like to test whether the above array contains an object with all the key/values as this partial object:

const obj = {
    "region": "London",
    "airport": "Heathrow",
    "messages": [
        {
            "region": "London",
            "message": "This is a test message"
        }
    ]
}

Note obj does not have all the properties from the objects in data and the same applies to the messages array - there are some properties missing (like date). To test whether data contains all the properties of obj, I tried the following:

const exists = data.some(0 => {
   return Object.keys(obj).some(k => {
       return Object.keys(o).indexOf(k)>-1 && obj[k]===o[k];
   });
});

The above only checks one level deep i.e. the messages array is not compared deeply.

Since I want this for Jest, I have also tried the following:

expect(data).toEqual(
   expect.arrayContaining([
       expect.objectContaining(obj)
   ])
);

The second approach above does not take into account the missing properties in the objects inside messages array.

Could someone please help me achieve the above?


Solution

  • Here is a solution if you have multiple objects in the nested array, for both data and obj to be compared with.

    const data = [{
        "region": "London",
        "code": "0",
        "airport": "Heathrow",
        "messages": [{
          "date": 1617063225,
          "region": "Londonn",
          "message": "This is a test messageee"
        },{
          "date": 1617063225,
          "region": "London",
          "message": "This is a test message"
        },{
          "date": 1617063225,
          "region": "London",
          "message": "This is a test message"
        }]
      },
      {
        "region": "London",
        "code": "1",
        "airport": "Heathrow",
        "messages": [{
          "date": 1617063226,
          "region": "London",
          "message": "This is a test message"
        },{
          "date": 1617063225,
          "region": "London",
          "message": "This is a test message"
        },{
          "date": 1617063225,
          "region": "London",
          "message": "This is a test message"
        }]
      }
    ]
    
    const obj = {
      "region": "London",
      "airport": "Heathrow",
      "messages": [{
        "region": "London",
        "message": "This is a test message"
      },{
        "region": "Londonn",
        "message": "This is a test messageee"
      },{
        "region": "London",
        "message": "This is a test message"
      }]
    }
    function compareObj(x, y) {
       let objectsAreSame = true;
       for(let prop in x) {
          if(x[prop] !== y[prop]) {
             objectsAreSame = false;
             break;
          }
       }
       return objectsAreSame;
    }
    const compare = (data, obj)=> {
      return data.some(o => {
        return Object.keys(obj).every(k => {
          if (Array.isArray(obj[k])) {
             let cond
              for(let i=0; i<obj[k].length; i++){
                o[k].some(el => {
                  return cond = compareObj(obj[k][i], el)
                })  
                if(cond === false) return cond
              }
              return cond;
          } else {
            return obj[k] === o[k]
          }
        });
      });
    }
    
    console.log(compare(data, obj))

    You can do something like this. But this only works if the nested array has only one object in it. You can adjust it though to loop through it if needed.

    const data = [{
        "region": "London",
        "code": "0",
        "airport": "Heathrow",
        "messages": [{
          "date": 1617063225,
          "region": "London",
          "message": "This is a test message"
        }]
      },
      {
        "region": "Londonn",
        "code": "1",
        "airport": "Heathrow",
        "messages": [{
          "date": 1617063226,
          "region": "London",
          "message": "This is a test messageee"
        }]
      }
    ]
    
    const obj = {
      "region": "London",
      "airport": "Heathrow",
      "messages": [{
        "region": "London",
        "message": "This is a test message"
      }]
    }
    
    const compare = (data, obj)=> {
      return data.some(o => {
        return Object.keys(obj).every(k => {
          if (Array.isArray(obj[k])) {
            return compare(o[k], obj[k][0])
          } else {
            return obj[k] === o[k]
          }
        });
      });
    }
    
    console.log(compare(data, obj))