JS change nested property - javascript

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);

Related

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

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

JavaScript filter instead map

I have this code:
const uniform = {
zone: 'BOTTOM'
}
const sizes = [
{
_id: 'sizeId2',
zones: ['BOTTOM'],
value: '48'
},
{
_id: 'sizeId3',
zones: ['BOTTOM'],
value: '42'
},
]
sizes.map((size) => (size.zones.includes(uniform.zone) ? {
_id: size._id,
value: size.value,
} : null))
https://jsfiddle.net/pmiranda/945fsdw7/5/
// here I'm trying another way than map and the ternary
console.log(sizes.filter((size) => (size.zones.includes(uniform.zone) && {
_id: size._id,
value: size.value,
})))
I wonder, how could I replace that map with a filter? Because I think that mapping with a ternary with null could be done in a better way, plus, in the map way I'm getting that null in the end, I want to not add it to the array
I think that you'd filter then map:
sizes.filter(size => size.zones.includes(uniform.zone)).map(size => ({
_id: size._id,
value: size.value,
}));
You probably need to return the result, or assign it to a variable.
const uniform = { zone: 'BOTTOM' }
const sizes = [
{
_id: 'sizeId2',
zones: ['BOTTOM'],
value: '48'
},
{
_id: 'sizeId3',
zones: ['BOTTOM'],
value: '42'
},
]
// reduce
const newSizes = sizes.reduce((acc, size) =>
{
if(size.zones.includes(uniform.zone)) {
acc.push(
{
_id: size._id,
value: size.value
})
}
return acc;
}, []
)
console.log(newSizes);
Using either map or filter does not make sense in the cuurent usecase as you are not utilizing the return value.
If you need to just loop over the array and create new entries (containing or nnot containing null) you can use forEach or reduce.
From the "comments", reduce is more suitable for you.
Without map and filter, just create new array
let newSizes = [];
sizes.forEach(({zones, _id, value}, key) => zones.includes(uniform.zone) && (newSizes[key] = {_id, value}))

How can I return only the string value of an object from a MongoDB array

valueOf() returns this:
[
{},
{ toUser: '5ed9d49c7e516616600eb693' },
{ toUser: '5ed9d49c7e516616600eb693' },
{ toUser: '5ed9d49c7e516616600eb693' },
{ toUser: '5ed9d3897e516616600eb692' }
]
I want to return only the value like "5ed9d3897e516616600eb692" or whatever toUser has. How?
This can be done in a couple of different ways, the best of which is using distinct:
db.collection.distinct("toUser")
Output will be:
[
'5ed9d49c7e516616600eb693',
'5ed9d49c7e516616600eb693',
'5ed9d49c7e516616600eb693',
'5ed9d3897e516616600eb692'
]
You can use reduce and inside callback check if the object has any key using Object.keys and length. If it has k then push the value using Object.values into the accumulator array
let data = [{},
{
toUser: '5ed9d49c7e516616600eb693'
},
{
toUser: '5ed9d49c7e516616600eb693'
},
{
toUser: '5ed9d49c7e516616600eb693'
},
{
toUser: '5ed9d3897e516616600eb692'
}
];
let filterdValue = data.reduce((acc, curr) => {
const objKey = Object.keys(curr);
if (objKey.length > 0) {
acc.push(...Object.values(curr))
}
return acc;
}, []);
console.log(filterdValue)
You can use following query to convert object to string
> db.objectidToStringDemo.aggregate([{$project: {toUser: {$toString: "$toUser"}}}]);

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;
}

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