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
}
}
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 plete, 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)?
Share Improve this question edited Feb 17, 2018 at 14:08 Doe asked Feb 17, 2018 at 13:53 DoeDoe 1934 silver badges14 bronze badges 5- 1 use library such as underscore or lodash. Don't re-invent the wheel. – Vladimir M Commented Feb 17, 2018 at 13:55
- 1 @VladimirM: Doesn't even remotely require a library. – T.J. Crowder Commented Feb 17, 2018 at 13:55
- 1 I have been working on it which is why i got stuck. Please check my updated Q for my partial solution @T.J.Crowder – Doe Commented Feb 17, 2018 at 14:01
- @T.J.Crowder this particular task may be simple enough to do without. My suggestion is based on the assumption, that there will be more plex tasks to be performed. – Vladimir M Commented Feb 17, 2018 at 14:02
- Hmm I see. I'll see what I can get out of lodash @VladimirM – Doe Commented Feb 17, 2018 at 14:04
5 Answers
Reset to default 5Using reduce
method you can get your object
var data = {
"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
}
};
var results = Object.keys(data).reduce(function(acc, val) {
if(data[val].userType === 'Patient') acc[val] = data[val];
return acc;
}, {});
console.log(results);
My guess is that filtering during parsing might be most efficient (haven't measured/paed 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.
You can solve this with for-in
or Object.keys
or (on modern JavaScript engines) Object.entries
.
for-in
provides a means of iterating through the object's enumerable properties; you can then use those property names to look up the value:
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
Live Example:
var 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
}
};
var result = {};
for (var key in users) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.keys
gives you an array of the object's own enumerable properties, so:
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
Live Example:
var 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
}
};
var result = {};
Object.keys(users).forEach(function(key) {
var entry = users[key];
if (entry.userType === "Patient") {
result[key] = entry;
}
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Object.entries
provides an iterable which consists of the name and value of each own, enumerable property. It's quite new. So for instance (in ES2015+ syntax where Object.entries
was added in ES2017 but can be polyfilled):
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
Live Example:
const 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
}
};
const result = {};
for (const [key, value] of Object.entries(users)) {
if (value.userType === "Patient") {
result[key] = value;
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
You can use reduce()
method on your object keys and build new object from that.
const obj = {"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}}}
const newObj = {
'UserCustom': Object.keys(obj.Users).reduce((r, k) => {
if(obj.Users[k].userType == 'Patient') r[k] = Object.assign({}, obj.Users[k])
return r;
}, {})
}
console.log(newObj)
Use for...in
to iterate through object and check if ther usertype is patient or not.
var users = {
"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
}
}
};
for(let user in users.Users){
if(users.Users.hasOwnProperty(user) && users.Users[user].userType!=="Patient")
delete users.Users[user];
}
console.log(users);
This will modify the object, if you want to preserve it then just do a deep copy of the original object.