How to get only true value key pair from array of objects - javascript

I have an array of object that is coming from some api.The data i am getting is like this. It has multiple values but i only want to show the user which access he has. Suppose a user have only read access so i want to show the user read key.
[
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
So, i want to get only the key value pair from this array which has true values so i can show the keys using Object.keys().
expected result
[{write:true}]
I have tried different array methods but didn't succeed, here how i was thinking to solve this problem but it's only returning last element value.
item.map(tab => {
return Object.keys(tab).reduce((acc: string, key) => {
if (tab[key]) {
acc[key] = tab[key];
}
return acc;
}, {});
}),

You can get rid of reduce by creating an object from filtered entries. Then just filter by true values.
data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
{
admin: false,
createdAt: "1234",
id: 8,
read: true,
write: true,
}
];
out = data.map(item => Object.fromEntries(Object.entries(item).filter(([key, value]) => value === true)));
console.log(out)

if (tab[key]) will be applied on any truthy value not just true, for example, not empty string is a truthy value, any number is a truthy value except zero.
So you need explicitly check if the value equal to true by if (tab[key] === true)
const data = [
{
admin: false,
createdAt: "2022-08-21T05:32:20.936Z",
id: 8,
read: false,
write: true,
},
];
const result = data.map(tab => {
return Object.keys(tab).reduce((acc, key) => {
if (tab[key] === true) {
acc[key] = tab[key];
}
return acc;
}, {});
})
console.log(result)
For shorthand use can use
const result = data.map(tab => Object.entries(tab).reduce((acc, [key, value]) => ({ ...acc, ...(value === true && { [key]: value }) }), {}));

You can get the keys you want by changing the 2nd parameter of the keyFilters function.
let tabs = [
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: false,write: true},
{admin: false,createdAt: "2022-08-21T05:32:20.936Z",id: 8,read: true,write: true}
];
let keyFilters = function(values, keys){
let filteredKeys = {}
Object.keys(values).map((key, index)=>{
if (keys.includes(key)){
filteredKeys[key] = values[key]
}
})
return filteredKeys;
}
let filters = tabs.map(tab=>keyFilters(tab, ["read", "write"]))
console.log(filters)
output
0:(2) {read: false, write: true}
1:(2) {read: true, write: true

Related

JS change nested property

I need to change a nested variable property. First check if it exists then change it to 'N/A' if necessary. This is what I have.
const json = {
isCat: {
isAvaliable: true,
count: 5
},
isDog: {
isAvaliable: true,
count: 10
},
isFrog: {
isAvaliable: false,
count: null
}
}
const newJson = { ...json }
if(!jsonObj.isCat.count) {
newJson = {...newJson, json.isCat.count: 'N/A'}
}
Im not sure how to set count lets say by goign directly to it and changing the value. It seems simple maybe im missing something.
I can see the value in the if statement but i cant make any changes to the actual property value itself. Basically if a value is null, change it to 'N/A'
Using Object.entries and Object.fromEntries you can map the old object to the new object. If the count property is truthy, i.e. not null then map it through, otherwise shallow copy the element and update the count property with the new "N/A" value. This avoids mutating your original object.
const newJson = Object.fromEntries(Object.entries(json).map(([key, value]) => ([
key,
value.count ? value : { ...value,
count: 'N/A'
}
])));
const json = {
isCat: {
isAvaliable: true,
count: 5
},
isDog: {
isAvaliable: true,
count: 10
},
isFrog: {
isAvaliable: false,
count: null
}
};
const newJson = Object.fromEntries(Object.entries(json).map(([key, value]) => ([
key,
value.count ? value : { ...value,
count: 'N/A'
}
])));
console.log(newJson);
You can use array reduce method. First get all the keys using Object.keys method. Then traverse the keys and check the count is null or not. If null then change it to 'N/A'.
const json = {
isCat: {
isAvaliable: true,
count: 5,
},
isDog: {
isAvaliable: true,
count: 10,
},
isFrog: {
isAvaliable: false,
count: null,
},
};
const ret = Object.keys(json).reduce((prev, c) => {
const p = prev;
if (!json[c].count) p[c] = { ...json[c], count: 'N/A' };
else p[c] = { ...json[c] };
return p;
}, {});
console.log(ret);
Another solution with reduce. Beware of it's comma operator in the return value.
const json = {isCat: {isAvaliable: true,count: 5,},isDog: {isAvaliable:true,count: 10,},isFrog: {isAvaliable: false,count: null,},};
const res = Object.keys(json).reduce((pV,cV)=>(json[cV].count==null?json[cV].count='N/A':null,json),{});
console.log(res);

How do I filter through an array list and return results that match the filter parameter?

I have a list that I'm filtering through to return results that are either, lessThan, greaterThan or equals to a particular value. But the function that does the comparison returns boolean values.
queryModifiers is an object of key value pairs that specifies what key within the data set is being compared and also the type of comparison.
const queryModifiers = {
price: "greaterThan",
weight: "lessThan",
}
const list = [
{
'2104a7bd-5e78-49ce-a1f6-0699ac98f264': {
additionalPrices: 0,
clientOrderNumber: 'N / A',
companyName: 'Test Company',
completeDate: 'Invalid date',
createdAt: '2019-09-08 16:41:43',
createdBy: 'test#test.com',
deliveryDate: '2019-09-14 16:39:25',
driver: 'Robert Kaszkiewicz',
dropOff: 'Avenida Callao 1234, Buenos Aires, Argentina',
height: 23,
isPreparingTrailer: true,
isSmsSent: true,
isTrailerReady: true,
key: '2104a7bd-5e78-49ce-a1f6-0699ac98f264',
notes: '',
pickUp: 'Poprad, Slovakia',
price: 1400,
quantity: 2,
trailer: 'einzeln',
vehicle: 'Sattel',
vehicleClass: 'Mega',
vehicleId: '12313',
vehicleReadyDate: '2019-09-27 16:41:22',
weight: 123
},
'388113f5-3927-4fe3-80d5-f2fcf1c7cedd': {
clientOrderNumber: 'N / A',
companyName: 'Test Company',
createdAt: '2019-09-26 18:32:18',
createdBy: 'test#test.com',
deliveryDate: '2019-09-20 18:31:45',
driver: 'Michal Kucharski',
dropOff: 'Logroño, Spain',
height: 0,
isPreparingTrailer: false,
isSmsSent: false,
isTrailerReady: false,
key: '388113f5-3927-4fe3-80d5-f2fcf1c7cedd',
notes: '',
orderId: '',
pickUp: '16671 Butano Place, Fontana, CA, USA',
price: 0,
quantity: 1,
trailer: '2er Pack',
vehicle: 'Sattel',
vehicleClass: 'Standard',
vehicleId: 'efgefg',
vehicleReadyDate: '2019-09-27 18:32:08',
weight: 0
},
'795e7531-8655-4e38-a576-e13483922607': {
clientOrderNumber: 'N / A',
companyName: 'Test Company',
createdAt: '2019-10-07 14:59:28',
createdBy: 'test#test.com',
deliveryDate: '2019-10-09 14:54:44',
driver: 'Pawel Marczyk',
dropOff: 'München, Germany',
height: 1150,
isPreparingTrailer: false,
isSmsSent: false,
isTrailerReady: false,
key: '795e7531-8655-4e38-a576-e13483922607',
notes: 'alle fertig, vorher anrufen',
orderId: '',
pickUp: 'Soest, Germany',
price: 5000,
quantity: 10,
trailer: '3er Pack',
vehicle: 'Sattel',
vehicleClass: 'Standard',
vehicleId: '1121+23+24',
vehicleReadyDate: '2019-10-07 14:55:19',
weight: 20000
},
] // list is an array of objects
export const handleFilterModifier = (value, compareValue, modifier) => {
if (modifier === 'lessThan') {
return value > compareValue;
}
if (modifier === 'equals') {
return value === compareValue;
}
if (modifier === 'greaterThan') {
return value < compareValue;
}
return null;
};
list.filter(
item => Object.entries(queryModifiers)
.every(([filterKey, filterVal]) => {
const compareValue = item[filterKey];
const value = Object.values(queryKeys);
const result = handleFilterModifier(
parseFloat(value),
compareValue,
filterVal
);
console.log(result); // result here returns boolean (true or false);
})
);
Where value is the parameter by which the list is being queried with e.g 100
compareValue is the data[key] value from the list that corresponds with the parameter being compared.
and modifier is the comparison method e.g greaterThan, lessThan or equals.
I want result to return list items that match and not boolean (which are actually correct when matched with the dataset).
It's not entirely clear what you're asking, but it seems to be that the console.log you have is returning a boolean, but you are expecting it to return a value, since you are trying to filter the list?
But actually, you probably do want it to return a boolean where it is. It is inside of an every function, which itself is inside of a filter function. The way every works is each iteration should return true or false (and if there are any falses, the whole thing returns false), and the way filter works is for each item, if you return true the item is saved into the resulting array. They both expect a boolean return.
list.filter(
item => Object.entries(queryModifiers)
.every(([filterKey, filterVal]) => {
const compareValue = item[filterKey];
const value = Object.values(queryKeys);
const result = handleFilterModifier(
parseFloat(value),
compareValue,
filterVal
);
})
);
Line by line:
list.filter : filter the list
item => Object.entries(queryModifiers) : set each item in the list to item, and then get the key pairs of the object, queryModifiers (which you haven't included here, by the way)
.every(([filterKey, filterVal]) => { : return true or false (i.e. keep or discard this item) if all of the queryModifiers key pairs sent into this function return true
const compareValue = item[filterKey]; : prepare a value
const value = Object.values(queryKeys); : prepare a value
const result = handleFilterModifier( ... ) : determine a true/false result
At this point result should be true or false, signifying whether this key/pair of queryModifiers passes your test, and it should be returned, i.e. return result; If all of them do, then the every function will return true, which means this iteration of the filter function will be included in the result.
So basically:
const resultList = list.filter(
item => Object.entries(queryModifiers)
.every(([filterKey, filterVal]) => {
const compareValue = item[filterKey];
const value = Object.values(queryKeys);
const result = handleFilterModifier(
parseFloat(value),
compareValue,
filterVal
);
return result;
})
);
console.log(resultList);
The section of code which returns boolean values is the following:
export const handleFilterModifier = (value,
compareValue, modifier) => {
if (modifier === 'lessThan') {
return value > compareValue;
}
if (modifier === 'equals') {
return value === compareValue;
}
if (modifier === 'greaterThan') {
return value < compareValue;
}
return null;
};
To say it in pure english: If the modifier is lessThan and the value is greater than the compare value it will return boolean true. If the modifier is equals and the values are equal it will return boolean true. If the modifier is greaterThan and value is less than compare value it will return boolean true. Maybe you need to have a good look at this code and fix it.

JS/TS how to iterate thru object array and change values

consider the following array.
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
What is the best way to build a function which can do the following goals?
1) will set all members to false
2) set chosen member to true ( passed as a parameter )
Absent more specific requirements, this is a bit of a choose-your-own-adventure.
(Note: For brevity this code uses ES6 computed property names and destructuring assignment and ES2018 object spread syntax, all of which can be transpiled by TypeScript.)
If each object has exactly one key
...and you want to mutate the original array and objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
const [key] = Object.keys(obj);
obj[key] = key === selectedKey;
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const [key] = Object.keys(obj);
newObjects.push({ [key]: key === selectedKey });
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
return objects.map(obj => {
const [key] = Object.keys(obj);
return { [key]: key === selectedKey };
});
}
console.log(selectKey(objects, 'userAssignment'))
If the objects can have more than one key
...and you want to mutate the original array and objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
for (let key of Object.keys(obj)) {
obj[key] = key === selectedKey;
}
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const newObj = {};
for (let key of Object.keys(obj)) {
newObj[key] = key === selectedKey;
}
newObjects.push(newObj);
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
return objects.map(obj =>
Object.keys(obj).reduce((newObj, key) =>
({ ...newObj, [key]: key === selectedKey }),
{}
)
);
}
console.log(selectKey(objects, 'userAssignment'))
You can iterate the array with Array.forEach(), get the key using Object.keys(), compare to the selected key, and set the value accordingly:
const routingButtonsHighlighter = [{vehicle: true}, {userAssignment: false}, {relations: false}];
const select = (arr, selectedKey) =>
arr.forEach((o) => {
const key = Object.keys(o)[0];
o[key] = key === selectedKey;
});
select(routingButtonsHighlighter, 'userAssignment');
console.log(routingButtonsHighlighter);
Creating a method for something like this would be highly specialized, so to abstract it, I've decided to write it like this:
function arrayFlagSinglePropertyTrue(key, arrayofobjects) {
for (let i in arrayofobjects) {
let keys = Object.keys(arrayofobjects[i]);
if (keys[0] == key) {
arrayofobjects[i][keys[0]] = true;
} else {
arrayofobjects[i][keys[0]] = false;
}
}
return arrayofobjects;
}
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
console.log(arrayFlagSinglePropertyTrue("relations", routingButtonsHighlighter));
Although this will get what you require done, its highly specialized and only works if the objects in the array contain one property or at the very least the first property in the object itself is the one you want to set to flag.
Edit: Some advice:
Uniformity in lists helps avoid the issue you have. By structuring your objects with uniform property names and then acting on the values themselves, you no longer require the use of specialized functions or code in order to modify it. At this point you can rely on fundamental programming logic to change the properties efficiently.
If you get the list from some external source and have no control over it, then you may need to either reorganize it yourself. If you can't then making specialized functions/codes is your last resort.
If possible, take something like this:
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
Organize it into something like this where the actual object properties are uniform:
let betterStructureObject = [
{ propertyName: "vehicle", status: true },
{ propertyName: "userAssignment", status: false },
{ propertyName: "vehicle", status: false },
]
So you can easily loop over it and not have to worry about writing specialized code.
for (let i in betterStructureObject) {
if (betterStructureObject[i].propertyName == "vehicle")
betterStructureObject[i].status = true;
else betterStructureObject[i].status = false;
}

Building adjacency matrix from an array of objects

I have a plain JavaScript array of objects, say e.g.
const drawings = [
{
name: "Foo",
category: "widget"
},
{
name: "Bar",
category: "widget"
},
{
name: "Bar",
category: "fidget"
},
]
etc, where both the name and category have duplicates. What I want to end up with is essentially a list of objects (this is to meet the interface for a 3rd party library), where each object represents a name, and then for each category there is a property that is either true or false, depending on the original list. So for the example the output would be:
const output = [
{
name: "Foo",
widget: true,
fidget: false
},
{
{
name: "Bar",
widget: true,
fidget: true
},
]
I would first go through and make an object of your categories with the categories as keys and default values as false.
Then you can assign this to each object and set the correct keys to true as you go through.
const drawings = [{name: "Foo",category: "widget"},{name: "Bar",category: "widget"},{name: "Bar",category: "fidget"},]
// make category object where everything is false
let category_obj = drawings.reduce((a, item) => (a[item.category] = false, a), {})
let output = drawings.reduce((a, {name, category}) => {
// assign cat
if (!a.hasOwnProperty(name)) a[name] = Object.assign({}, {name}, category_obj)
// set to true if the correct category
a[name][category] = true
return a
}, {})
// the above makes an object, but you only want the array of values
console.log(Object.values(output))
If you already know the categories or if you have infered them as you suggested, you could use Array.reduce() like such:
drawings.reduce(function(acc, curr) {
if (!acc.some(elt => elt.name === curr.name)) {
acc.push({name: curr.name, widget: false, fidget: false})
}
const i = acc.findIndex(elt => elt.name === curr.name)
acc[i][curr.category] = true
return acc
}, [])

javascript constructing new object using reduce method

Hello Im stuck with constructing a new object based on the backend respond.
Here is the respond that i've receive
acl:[
{
"user_type":5,
"user_id":"c7e5cb45ba764ad7ad29b5bdd4f12128",
"user_name":"John",
"view":true,
"modify":false,
"remove":false,
"modify_acl":false
},
{
"user_type":5,
"user_id":"f673beac0245462f8c71066536049e72",
"user_name":"Allan",
"view":true,
"modify":true,
"remove":true,
"modify_acl":false
}]
The requirement was to filter the respond to remove all of the properties with false value and construct a new array that hold the access control value (acl).The expected new object will be like this:
[
{
"userType":5,
"label":"c7e5cb45ba764ad7ad29b5bdd4f12128",
"value":"John",
"acl":[
{"value":"view", "label":"View"}
]
},
{
"userType":5,
"label":"f673beac0245462f8c71066536049e72",
"value":"Allan",
"acl":[
{"value":"view", "label":"View"},
{"value":"modify", "label":"Modify"},
{"value":"remove", "label":"Remove"}
]
}
]
Currently i'm using reduce method to remove all the false value. But I'm stuck to construct the expected result.
You could check the type of the property and take boolean for assigning a new label/value pair and omit false values. Otherwise take the key value pair and assign it to the actual object.
Array#map is actually the better method of choice, because it returns an array, which is wanted.
By using Array#reduce, the accumulator would never change, because it would be an array.
var acl = [{ user_type: 5, user_id: "c7e5cb45ba764ad7ad29b5bdd4f12128", user_name: "John", view: true, modify: false, remove: false, modify_acl: false }, { user_type: 5, user_id: "f673beac0245462f8c71066536049e72", user_name: "Allan", view: true, modify: true, remove: true, modify_acl: false }],
result = acl.map(o => {
var r = {},
acl = [];
Object.entries(o).forEach(([k, v]) => {
if (typeof v === 'boolean') {
v && acl.push({ value: k, label: v });
} else {
r[k] = v;
}
});
return Object.assign(r, { acl });
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories