Search code examples
javascriptecmascript-3

Group and filter items from an array


I have an array called items, here is a sampel of the data inside the array:

[
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"attempted"
   },
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"waiting"
   },
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"completed"
   },
   {
      "id":"123",
      "key":"xxx222@gmail.com",
      "status":"completed"
   },
   {
      "id":"456",
      "key":"xxx333@gmail.com",
      "status":"waiting"
   },
   {
      "id":"456",
      "key":"xxx444@gmail.com",
      "status":"attempted"
   },
   {
      "id":"456",
      "key":"xxx444@gmail.com",
      "status":"failed"
   },
   {
      "id":"456",
      "key":"xxx555@gmail.com",
      "status":"attempted"
   },
   {
      "id":"456",
      "key":"xxx555@gmail.com",
      "status":"waiting"
   }
]

I would like to group and filter items from my array. I have figured out that I could create a second array and push all items that match my criteria into that second array, but unsure how to achieve this.

Here are the criteria for grouping and filtering:

  1. Group by id and key so that all records with the same id and key are grouped together and can be filtered in the next step. So here I could dynamically create arrays and they would look like this:

Array 1:

[
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"attempted"
   },
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"waiting"
   },
   {
      "id":"123",
      "key":"xxx111@gmail.com",
      "status":"completed"
   }
]

Array 2:

[
   {
      "id":"123",
      "key":"xxx222@gmail.com",
      "status":"completed"
   }
]

Array 3:

[
   {
      "id":"456",
      "key":"xxx333@gmail.com",
      "status":"waiting"
   }
]

Array 4:

[
   {
      "id":"456",
      "key":"xxx444@gmail.com",
      "status":"attempted"
   },
   {
      "id":"456",
      "key":"xxx444@gmail.com",
      "status":"failed"
   }
]

Array 5:

[
   {
      "id":"456",
      "key":"xxx555@gmail.com",
      "status":"attempted"
   },
   {
      "id":"456",
      "key":"xxx555@gmail.com",
      "status":"waiting"
   }
]
  1. Above arrays should be filtered by status: if in an array I have either statuses failed or completed I do not want to consider this array anymore. Data from arrays that qualify could be pushed to my final array and I just need the id and key filed, I don't need to see the different statuses:

Final array:

[
   {
      "id":"456",
      "key":"xxx333@gmail.com"
   },
   {
      "id":"456",
      "key":"xxx555@gmail.com"
   }
]

So far I have tried this, but I am unable to get the desired results:

  if(items.length >= 1) {
      for (i = 0; i < items.length; i++) {
        key = items[i]["key"];
        status = items[i]["status"];
        id = items[i]["id"];

        var arr=[];
        if(items[i]["key"]==key && items[i]["id"]==id) {
          arr.push(items[i]["key"])
          arr.push(items[i]["id"])
        }
}

Any help would be appreciated.


Solution

  • You could group, filter and map the arrays with array with objects without status.

    const
        data = [{ id: "123", key: "xxx111@gmail.com", status: "attempted" }, { id: "123", key: "xxx111@gmail.com", status: "waiting" }, { id: "123", key: "xxx111@gmail.com", status: "completed" }, { id: "123", key: "xxx222@gmail.com", status: "completed" }, { id: "456", key: "xxx333@gmail.com", status: "waiting" }, { id: "456", key: "xxx444@gmail.com", status: "attempted" }, { id: "456", key: "xxx444@gmail.com", status: "failed" }, { id: "456", key: "xxx555@gmail.com", status: "attempted" }, { id: "456", key: "xxx555@gmail.com", status: "waiting" }],
        keys = ['id', 'key'],
        unwanted = ['failed', 'completed'],
        result = Object
            .values(data.reduce((r, o) => {
                const key = keys.map(k => o[k]).join('|');
                if (!r[key]) r[key] = [];
                r[key].push(o);
                return r;
            }, []))
            .filter(a => a.every(({ status }) => !unwanted.includes(status)))
            .map(a => a.map(({ status, ...rest }) => rest));
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    In really old JS

    var data = [{ id: "123", key: "xxx111@gmail.com", status: "attempted" }, { id: "123", key: "xxx111@gmail.com", status: "waiting" }, { id: "123", key: "xxx111@gmail.com", status: "completed" }, { id: "123", key: "xxx222@gmail.com", status: "completed" }, { id: "456", key: "xxx333@gmail.com", status: "waiting" }, { id: "456", key: "xxx444@gmail.com", status: "attempted" }, { id: "456", key: "xxx444@gmail.com", status: "failed" }, { id: "456", key: "xxx555@gmail.com", status: "attempted" }, { id: "456", key: "xxx555@gmail.com", status: "waiting" }],
        keys = ['id', 'key'],
        unwanted = ['failed', 'completed'],
        temp = {},
        result = [],
        i, j, k, key;
    
    outer: for (i = 0; i < data.length; i++) {
        key = '';
    
        for (j = 0; j < keys.length; j++) key += data[i][keys[j]] + '|';
    
        if (temp[key] === null) continue;
    
        if (temp[key] === undefined) temp[key] = [];
    
        for (j = 0; j < unwanted.length; j++) {
            if (data[i].status !== unwanted[j]) continue;
            temp[key] = null;
            continue outer;
        }
    
        temp[key].push({ id: data[i].id, key: data[i].key });
    }
    
    for (k in temp) {
        if (temp[k]) result.push(temp[k]);
    }
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }