How to retrieve a particular property from array of objects based on multiple conditions using react and javascript?

Viewed 63

i have an array of objects like below,

const arr_obj = [
    {
        id: '1',
        jobs: [
            {
                completed: false,
                id: '11',
                run: {
                    id: '6',
                    type: 'type1',
                },
            },
            {
                 completed: true,
                 id: '14',
                 run: {
                     id: '17',
                     type: 'type1',
                 },

             },
             {
                 completed: false,
                 id: '12',
                 run: {
                     id: '7',
                     type: 'type2',
                 },
             },
         ],
     },
     {
         id: '2',
         jobs: [
             {
                 completed: true,
                 id: '13',
                 run: {
                     id: '8',
                     type: 'type2',
                 },
             },
             {
                 completed: true,
                 id: '16',
                 run: {
                     id: '9',
                     type: 'type1',
                 },

             }, 
             {
                 completed: true,
                 id: '61',
                 run: {
                     id: '19',
                     type: 'type1',
                 },
             },
         ],
     },
     {
         id: '3',
         jobs: [
             {
                 completed: false,
                 id: '111',
                 run: {
                     id: '62',
                     type: 'type1',
                 },
             },
         ],
     },
 ],

and an arr_ids = ["1","2"]

now i have to filter those ids from arr_obj matchings arr_ids which i do like so

const filteredIds = arr_obj.filter(obj => arr_ids.includes(obj.id));


so the filtered_arrobj = [
     {
         id: '1',
         jobs: [
             {
                 completed: false,
                 id: '11',
                 run: {
                     id: '6',
                     type: 'type1',
                 },
             },
             {
                 completed: true,
                 id: '14',
                 run: {
                     id: '17',
                     type: 'type1',
                 },

             },
             {
                 completed: false,
                 id: '12',
                 run: {
                     id: '7',
                     type: 'type2',
                 },
             },
         ],
     },
     {
         id: '2',
         jobs: [
             {
                 completed: true,
                 id: '13',
                 run: {
                     id: '8',
                     type: 'type2',
                 },
             },
             {
                 completed: true,
                 id: '16',
                 run: {
                     id: '9',
                     type: 'type1',
                 },

             }, 
             {
                 completed: true,
                 id: '61',
                 run: {
                     id: '19',
                     type: 'type1',
                 },
             },
         ],
     },  
     ]

Now i will have to get the ids from filtered_arrobj whose runs are of type "type1" and none of the jobs have completed: false.

so the expected output from filtered_arrobj is "2"

here in the above example id "1" is not taken because id "1" has job completed: true but it also has job completed: false for type "type1".

what i have tried?

const output = filtered_arrobj.map(obj => obj.jobs.map(job => job.run.type === 
"type1" && job.completed === true));
        


when i log the output its gives like so

[ 
    [false,true,false],
    [true,true,true]
]

this not giving me the id of the obj whose job has run of type = "type1" and which has no jobs completed: false.

how can i get that. could someone help me with this. I am new to programming and learning on the go. thanks.

6 Answers

This example iterates over the data array with a simple for...of loop and uses every to check the required conditions.

const data=[{id:"1",jobs:[{completed:false,id:"11",run:{id:"6",type:"type1"}},{completed:true,id:"14",run:{id:"17",type:"type1"}},{completed:false,id:"12",run:{id:"7",type:"type2"}}]},{id:"2",jobs:[{completed:true,id:"13",run:{id:"8",type:"type2"}},{completed:true,id:"16",run:{id:"9",type:"type1"}},{completed:true,id:"61",run:{id:"19",type:"type1"}}]}];

let out = [];

for (let obj of data) {

  // Find out if the jobs of type1 have all completed...
  const runCompleted = obj.jobs.every(job => {
    return job.completed && job.run.type === 'type1';
  });

  // If not add the id to the output array
  if (!runCompleted) out.push(obj.id);
}

// And then you just check the length of the array
console.log(out);
console.log(out.length);

Use Array.filter() on arrObj filtered by arrIds which you already did, after that filter for jobs array (inside above filter) which contains type as type1 and then check if filtered jobs has completed as true then return true otherwise false.

const arrObj = [
  {
    id: '1',
    jobs: [
      {
        completed: false,
        id: '11',
        run: {
          id: '6',
          type: 'type1',
        },
      },
      {
        completed: true,
        id: '14',
        run: {
          id: '17',
          type: 'type1',
        },

      },
      {
        completed: false,
        id: '12',
        run: {
          id: '7',
          type: 'type2',
        },
      },
    ],
  },
  {
    id: '2',
    jobs: [
      {
        completed: true,
        id: '13',
        run: {
          id: '8',
          type: 'type2',
        },
      },
      {
        completed: true,
        id: '16',
        run: {
          id: '9',
          type: 'type1',
        },

      },
      {
        completed: true,
        id: '61',
        run: {
          id: '19',
          type: 'type1',
        },
      },
    ],
  },
  {
    id: '3',
    jobs: [
      {
        completed: false,
        id: '111',
        run: {
          id: '62',
          type: 'type1',
        },
      },
    ],
  },
];

const arrIds = ["1", "2"];

const filteredIds = arrObj.filter(obj => {
  if (arrIds.includes(obj.id)) {
    const jobs = obj.jobs.filter(job => job.run.type === "type1");
    if (jobs.length > 0) {
      return jobs.every(job => job.completed === true);
    }
    return false;
  }
  return false;
});

console.log(filteredIds);

I would do it in one iteration, something like this:

const output = arr_obj.filter(obj => {
    let hasType1 = false;
    return (
        arr_ids.includes(obj.id) &&
        obj.jobs.every(job => {
            if (job.run.type === 'type1') hasType1 = true;
            return job.completed === true;
        }) &&
        hasType1
    );
});

Or if you only need to check for completeness on type1 jobs:

const output = arr_obj.filter(obj => {
    let hasType1 = false;
    return (
        arr_ids.includes(obj.id) &&
        obj.jobs.every(job => {
            if (job.run.type === 'type1') {
                hasType1 = true;
                return job.completed === true;
            }
            return true;
        }) &&
        hasType1
    );
});

This should work :

const arr = arr_obj.reduce((accumulator, current) => {
    const doSatisfyCondition = arr_ids.includes(current.id) && current.jobs.every(item => item.completed) && current.jobs.some(item => item.run.type === "type1")
    if (doSatisfyCondition) accumulator.push(current.id);
    return accumulator;

}, [])
console.log(arr)```

Does this do the job?

const ids = new Set(arr_ids);
const filtered_objects = arr_obj.filter(el => ids.has(el.id));

The Set constructor creates a Set of Ids insread of an array. This enables you to use the has-function to check if the id property of the element coming from the arr_obj array is in the set "ids".

If you are new to programming you could check in to the Set and Map data structure and its related functions. There are some really good ways to filter and merge data if you can create some kind of uniqueness for every element in the array that you want to create a set from. In this example the Id is a good unique value.

This code solves the problem, it is a bit focused on optimization but it works.

const arr=[{id:"1",jobs:[{completed:!1,id:"11",run:{id:"6",type:"type1"}},{completed:!0,id:"14",run:{id:"17",type:"type1"}},{completed:!1,id:"12",run:{id:"7",type:"type2"}}]},{id:"2",jobs:[{completed:!0,id:"13",run:{id:"8",type:"type2"}},{completed:!0,id:"16",run:{id:"9",type:"type1"}},{completed:!0,id:"61",run:{id:"19",type:"type1"}}]},{id:"3",jobs:[{completed:!1,id:"111",run:{id:"62",type:"type1"}}]}];
 
// For optimitation
const targets = ["1", "2"].reduce((a, c) => ({...a, [c]: true}), {})

const result = arr.filter(data => {
  if(targets[data.id]) {
    let containType1 = false
    const jobs = data.jobs
    
    const canSave = jobs.every(job => {
      const isType1 = job.run.type === "type1"
      containType1 = isType1 ? true : containType1
      return isType1 ? job.completed : true
    })
    
    return canSave && containType1
  }
  
  return false
})
 
console.log(result)

Related