Search code examples
javascriptjsonobjectfilterobject-properties

How to filter an object of objects efficiently?


This question has been proposed many times in SO, but they all refer to an array of objects.

In my case, I would like to filter an object of objects.

Say I have this object:

"Users": {
  "w14FKo72BieZwbxwUouTpN7UQm02": {
    "name": "Naseebullah Ahmadi",
    "userType": "Patient",
    "writePermission": false
  },
  "SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
    "name": "Levi Yeager",
    "userType": "Patient",
    "writePermission": false
  },
  "VoxHFgUEIwRFWg7JTKNXSSoFoMV2": {
    "name": "Ernest Kamavuako",
    "userType": "Doctor",
    "writePermission": true
  },
  "hFoWuyxv6Vbt8sEKA87T0720tXV2": {
    "name": "Karla Stanlee",
    "userType": "Doctor",
    "writePermission": true
  }
}

I would like to filter this so I can get the following:

"UsersCustom": {
  "w14FKo72BieZwbxwUouTpN7UQm02": {
    "name": "Naseebullah Ahmadi",
    "userType": "Patient",
    "writePermission": false
  },
  "SXMrXfBvexQUXfnVg5WWVwsKjpD2": {
    "name": "Levi Yeager",
    "userType": "Patient",
    "writePermission": false
  }
}

What's the point of doing this?

Note that this object "User" is huge in reality (over 1000 entries) and each user has more attributes than mere "name", "userType", and "writePermission".

The reason why I need to filter the user's object is so that I can get users who are only (Patient) and get the id of that Patient to lookup in another object and finally merge them all in one object.

What I have so far

// user is the object as seen above
let Patients = users ? (
  // I loop through them
  Object.keys(users).map((uid, i) => {
    // get individual patient
    const patient = users[uid];
    // check their userType
    if (patient.userType === "Patient") {
      let customPatient = {
        uid: uid,
        name: patient.name,
        profession: patient.profession,
        history: null,
        ecg: null,
        heartSound: null
      };

      this._healthRef(uid).then(health => {
        customPatient.history = health;
        return this._heartSoundRef(uid).then(HS => HS);
      }).then(HS => {
        customPatient.heartSound = HS;
        return this._ecgRef(uid).then(a => a);
      }).then(ecg => {
        customPatient.ecg = ecg;
      }).then(() => {
        cusomPatients.push(customPatient);
      })
    }
  })
)

My solution above is, although partially complete, is still not efficient and wrong. Because I need the Id of each patient for other lookup

Update

Currently, most solution provides looping through the entries, which means that it will run O(n) in worst case. Is there any possibility that it can be solved quicker than O(n)?


Solution

  • My guess is that filtering during parsing might be most efficient (haven't measured/compaed it):

    j = '{"w14FKo72BieZwbxwUouTpN7UQm02":{"name":"Naseebullah Ahmadi","userType":"Patient","writePermission":false},"SXMrXfBvexQUXfnVg5WWVwsKjpD2":{"name":"Levi Yeager","userType":"Patient","writePermission":false},"VoxHFgUEIwRFWg7JTKNXSSoFoMV2":{"name":"Ernest Kamavuako","userType":"Doctor","writePermission":true},"hFoWuyxv6Vbt8sEKA87T0720tXV2":{"name":"Karla Stanlee","userType":"Doctor","writePermission":true}}'
    
    o = JSON.parse(j, (k, v) => !v.userType || v.userType === 'Patient' ? v : void 0)
    
    console.log(o)

    Caching the filtered object would be even more efficient to reduce network traffic.