I am trying to iterate a JSON object which is an array of categories.The categories may or may not have the subcategory.
If
hasSubcategory = false ,
then category id should be stored in final array.
If hasSubcategory = true ,it should iterate until the subcategory becomes hasSubcategory = false and store id in
final array.
There is parentId field to represent the parent category of the category.
More Importantly there may be sub categories for a single sub category
The final array should only be have the id of categories with hasSubcategory = false .
I would advise to chain filter + map methods:
const arr = [
{
"_id": "1",
"name": "DESKTOP COMPUTERS",
"hasSubCategory": "true",
"parentId": "0"
},
{
"_id": "2",
"name": "LAPTOP COMPUTERS",
"hasSubCategory": "false",
"parentId": "1"
},
{
"_id": "3",
"name": "MONITORS",
"hasSubCategory": "false",
"parentId": "2"
},
{
"_id": "4",
"name": "INPUT DEVICES",
"hasSubCategory": "true",
"parentId": "0"
},
{
"_id": "5",
"name": "PRINTERS SCANNERS",
"hasSubCategory": "false",
"parentId": "4"
},
{
"_id": "6",
"name": "ACCESSORIES",
"hasSubCategory": "false",
"parentId": "4"
},
];
const result = arr.filter(el => el.hasSubCategory === 'false').map(el => el._id);
console.log(result);
This is really simple - just use filter to extract the items with hasSubCategory of false, then map out the _id:
const arr = [{"_id":"1","name":"DESKTOP COMPUTERS","hasSubCategory":"true","parentId":"0"},{"_id":"2","name":"LAPTOP COMPUTERS","hasSubCategory":"false","parentId":"1"},{"_id":"3","name":"MONITORS","hasSubCategory":"false","parentId":"2"},{"_id":"4","name":"INPUT DEVICES","hasSubCategory":"true","parentId":"0"},{"_id":"5","name":"PRINTERS SCANNERS","hasSubCategory":"false","parentId":"4"},{"_id":"6","name":"ACCESSORIES","hasSubCategory":"false","parentId":"4"}];
const res = arr.filter(({ hasSubCategory }) => hasSubCategory == "false").map(({ _id }) => _id);
console.log(res);
For a more efficient solution, use reduce:
const arr = [{"_id":"1","name":"DESKTOP COMPUTERS","hasSubCategory":"true","parentId":"0"},{"_id":"2","name":"LAPTOP COMPUTERS","hasSubCategory":"false","parentId":"1"},{"_id":"3","name":"MONITORS","hasSubCategory":"false","parentId":"2"},{"_id":"4","name":"INPUT DEVICES","hasSubCategory":"true","parentId":"0"},{"_id":"5","name":"PRINTERS SCANNERS","hasSubCategory":"false","parentId":"4"},{"_id":"6","name":"ACCESSORIES","hasSubCategory":"false","parentId":"4"}];
const res = arr.reduce((a, { hasSubCategory, _id }) => (hasSubCategory == "false" ? a.push(_id) : a, a), []);
console.log(res);
Filter first to get the objects you need, then map them into the pattern you need.
let arr = [{"_id":"1","name":"DESKTOP COMPUTERS","hasSubCategory":"true","parentId":"0"},{"_id":"2","name":"LAPTOP COMPUTERS","hasSubCategory":"false","parentId":"1"},{"_id":"3","name":"MONITORS","hasSubCategory":"false","parentId":"2"},{"_id":"4","name":"INPUT DEVICES","hasSubCategory":"true","parentId":"0"},{"_id":"5","name":"PRINTERS SCANNERS","hasSubCategory":"false","parentId":"4"},{"_id":"6","name":"ACCESSORIES","hasSubCategory":"false","parentId":"4"}];
res = arr.filter(v => v.hasSubCategory === "false").map(e => Number(e._id))
console.log(res) // [ 2, 3, 5, 6 ]
Alternatively you can use reduce too:
let arr = [{"_id":"1","name":"DESKTOP COMPUTERS","hasSubCategory":"true","parentId":"0"},{"_id":"2","name":"LAPTOP COMPUTERS","hasSubCategory":"false","parentId":"1"},{"_id":"3","name":"MONITORS","hasSubCategory":"false","parentId":"2"},{"_id":"4","name":"INPUT DEVICES","hasSubCategory":"true","parentId":"0"},{"_id":"5","name":"PRINTERS SCANNERS","hasSubCategory":"false","parentId":"4"},{"_id":"6","name":"ACCESSORIES","hasSubCategory":"false","parentId":"4"}];
res = arr.reduce((a,c) => {if (c.hasSubCategory === "false") a.push(Number(c._id)); return a;}, [])
console.log(res)
Related
I have the following array
Array["MyArray",
{
"isLoaded":true,
"items":
[{
"id":"4",
"name":"ProductA",
"manufacturer":"BrandA",
"quantity":1,
"price":"25"
},{
"id":"1",
"name":"ProductB",
"manufacturer":"BrandB",
"quantity":5,
"price":"20"
}],
"coupons":null
}
]
I need to load product names and their quantity from the array.
const result = [key, value].map((item) => `${item.name} x ${item.quantity}`);
Here's one possible way to achieve the desired result:
const getProductsAndQuantity = ([k , v] = arr) => (
v.items.map(it => `${it.name} x ${it.quantity}`)
);
How to use it within the context of the question?
localforage.iterate(function(value, key, iterationNumber) {
console.log([key, value]);
const val2 = JSON.parse(value);
if (val2 && val2.items && val2.items.length > 0) {
console.log(val2.items.map(it => `${it.name} x ${it.quantity}`).join(', '))
};
});
How it works?
Among the parameters listed in the question ie, value, key, iterationNumber, only value is required.
The above method accepts the key-value pair as an array (of 2 elements) closely matching the console.log([key, value]); in the question
It uses only v (which is an object). On v, it accesses the prop named items and this items is an Array.
Next, .map is used to iterate through the Array and return each product's name and quantity in the desired/expected format.
Test it out on code-snippet:
const arr = [
"MyArray",
{
"isLoaded": true,
"items": [{
"id": "4",
"name": "ProductA",
"manufacturer": "BrandA",
"quantity": 1,
"price": "25"
}, {
"id": "1",
"name": "ProductB",
"manufacturer": "BrandB",
"quantity": 5,
"price": "20"
}],
"coupons": null
}
];
const getProductsAndQuantity = ([k, v] = arr) => (
v.items.map(
it => `${it.name} x ${it.quantity}`
)
);
console.log(getProductsAndQuantity());
I understood. You should learn about array methods such as map, filter, reduce. Here you go...
const items = [{
"id":"4",
"name":"ProductA",
"manufacturer":"BrandA",
"quantity":1,
"price":"25"
},{
"id":"1",
"name":"ProductB",
"manufacturer":"BrandB",
"quantity":5,
"price":"20"
}];
const result = items.map((item) => `${item.name} x ${item.quantity}`);
console.log(result);
I think I understand the question to say that the input is an array of objects, each containing an array of items. The key is that a nested array requires a nested loop. So, we iterate the objects and their internal items (see the lines commented //outer loop and // inner loop below)
Also, half-guessing from the context, it looks like the that the OP aims to assemble a sort of invoice for each object. First a demo of that, (and see below for the version simplified to exactly what the OP asks)...
const addInvoice = obj => {
let total = 0;
// inner loop
obj.invoice = obj.items.map(i => {
let subtotal = i.quantity * i.price;
total += subtotal
return `name: ${i.name}, qty: ${i.quantity}, unit price: ${i.price}, subtotal: ${subtotal}`
});
obj.invoice.push(`invoice total: ${total}`);
}
const objects = [{
"isLoaded": true,
"items": [{
"id": "4",
"name": "ProductA",
"manufacturer": "BrandA",
"quantity": 1,
"price": "25"
}, {
"id": "1",
"name": "ProductB",
"manufacturer": "BrandB",
"quantity": 5,
"price": "20"
}],
"coupons": null
}]
// outer loop
objects.forEach(addInvoice);
console.log(objects);
If my guess about the goal went to far, just remove the unit price, subtotal and total lines from the invoice function...
const objects = [{
"isLoaded": true,
"items": [{
"id": "4",
"name": "ProductA",
"manufacturer": "BrandA",
"quantity": 1,
"price": "25"
}, {
"id": "1",
"name": "ProductB",
"manufacturer": "BrandB",
"quantity": 5,
"price": "20"
}],
"coupons": null
}]
const summaryString = obj => {
return obj.items.map(i => `${i.name}, ${i.quantity}`);
}
const strings = objects.map(summaryString);
console.log(strings);
I'm writing a code where I need to filter a JSON array and update a value of a key. Here is my code.
var data = [{
"Id": "1",
"ab": '123',
"afb_Educational_expense_types_for_school__c": "Books or supplies"
}, {
"Id": "2",
"ab": '343',
"afb_Educational_expense_types_for_school__c": "Mandatory fees"
}, {
"Id": "3",
"ab": '34',
}];
var itemVar = data.filter(item => item.Id == '3');
itemVar['ab'] = '22';
console.log(itemVar);
Here I'm trying to set 'ab' to 22 but it is not working. Where am I going wrong?
Your itemVar is an array, because .filter always returns an array. You have to specify that you want the first element in the array [0]
itemVar[0]['ab'] = '22';
You can use findIndex and then update the relevant item of the array:
const data = [
{ "Id": "1", "ab": '123', "afb_Educational_expense_types_for_school__c": "Books or supplies" },
{ "Id": "2", "ab": '343', "afb_Educational_expense_types_for_school__c": "Mandatory fees" },
{ "Id": "3", "ab": '34' }
];
let index = data.findIndex((item) => item.Id == '3');
if (index !== -1) data[index].ab = '22';
console.log(data);
var itemVar = data.find((item) => item.Id == '3')
itemVar.ab = '22'
Thats the easiest way to solve it.
I have below array. First object is the original data. Inside array is the changed value. I am trying to create a final data by matching with the Name field with inside array. which should look like
var a =
[
{"Id":"1","Test":"Name1","Name":"hunt9988ggggggggggggdfsf1111"},
{"Id":"2","Test":"Name2","Name":"hunt9988ggggggggggggdfsf"},
[
**{"Name":"hunt9988ggggggggggggdfsf1118","Id":"1"}, // Changed value
{"Name":"hunt9988ggggggggggggdfsf1118","Id":"2"}**
]
]
Final Data
var a =
[
{"Id":"1","Test":"Name1","Name":"hunt9988ggggggggggggdfsf1118"},
{"Id":"2","Test":"Name2","Name":"hunt9988ggggggggggggdfsf1118"}
]
I am trying with below code
var result = a.map(item => ({ value: item.Id, text: item.Name}));
console.log(result)
Like this?
Note I modify the original array
let a = [{
"Id": "1",
"Test": "Name1",
"Name": "hunt9988ggggggggggggdfsf1111"
},
{
"Id": "2",
"Test": "Name2",
"Name": "hunt9988ggggggggggggdfsf"
},
[{
"Name": "hunt9988ggggggggggggdfsf1118",
"Id": "1"
}, // Changed value
{
"Name": "hunt9988ggggggggggggdfsf1118",
"Id": "2"
}
]
]
const replaceArray = a.find(item => Array.isArray(item))
replaceArray.forEach(item => a.find(aItem => aItem.Id === item.Id).Name=item.Name)
a = a.filter(item => item.Id)
console.log(a)
This is my array:
const
array1 = [
{
"value": "0",
"name": "5",
"waste": "remove",
"city": "NY"
},
{
"value": "0",
"name": "51",
"waste": "remove",
}
]
So now, i wanted to remove certain and form a new array with objects: For example, i need to remove "Waste & value" and keep rest of the things, so i used this code:
var keys_to_keep = ['name', 'city']
const result = array2.map(e => {
const obj = {};
keys_to_keep.forEach(k => obj[k] = e[k])
return obj;
});
console.log(result)
And it gives a output as
[ { name: '5', city: 'NY' }, { name: '51', city: undefined } ]
Now as you can see city with undefined value, how to remove that ? i mean filter this and just show keys with value,
So my question is how to filter undefined and also is there any other better solution for removing unwanted object keys and showing new array with wanted keys ? or the method am using is performant enough ?
You can check if the value is undefined in your forEach:
const result = array2.map(e => {
const obj = {};
keys_to_keep.forEach(k => {
if (undefined !== e[k]) {
obj[k] = e[k]
}
)
return obj;
});
You can check if e[k] is defined before you add it to obj by checking whether the e object has the property k using .hasOwnProperty():
const array = [{ "value": "0", "name": "5", "waste": "remove", "city": "NY" }, { "value": "0", "name": "51", "waste": "remove", } ];
const keys_to_keep = ['name', 'city'];
const result = array.map(e => {
const obj = {};
keys_to_keep.forEach(k => {
if (e.hasOwnProperty(k))
obj[k] = e[k]
});
return obj;
});
console.log(result)
If the keys you want to remove aren't dynamic, you can also use destructuring assignment to pull out the properties you want to discard, and use the rest syntax to obtain an object without those properties:
const array = [{ "value": "0", "name": "5", "waste": "remove", "city": "NY" }, { "value": "0", "name": "51", "waste": "remove", } ];
const result = array.map(({value, waste, ...r}) => r);
console.log(result)
I am going to answer both the parts. So here are the steps to do that.
Use map() on the main array.
Get entries of each object using Object.entries().
Apply filter() on entires array are remove those entires for which key is not present in keys_to_keep
Now for the second part.
Using keys_to_keep create an object which contain undefined values for each key.
Use map() again on prev result and use Spread operator. First spread the object created above and then spread the original values. This way if any key is not found it will be set to undefined
const
array1 = [
{
"value": "0",
"name": "5",
"waste": "remove",
"city": "NY"
},
{
"value": "0",
"name": "51",
"waste": "remove",
}
]
var keys_to_keep = ['name', 'city']
let obj = Object.fromEntries(keys_to_keep.map(x => [x, undefined]));
const res = array1.map(obj =>
Object.fromEntries(
Object.entries(obj).filter(([k, v]) => keys_to_keep.includes(k))))
.map(x => ({...obj, ...x}))
console.log(res)
You can use .map to iterate over the objects, Object.entries to get the key-value pairs of each item, Object.fromEntries to group them into the resulting objects, and .filter to get only the entries with a key in keys_to_keep and a value that is not undefined:
const array1 = [
{ "value": "0", "name": "5", "waste": "remove", "city": "NY" },
{ "value": "0", "name": "51", "waste": "remove" }
];
var keys_to_keep = ['name', 'city'];
const result = array1.map(item =>
Object.fromEntries(
Object.entries(item).filter(([key, value]) =>
keys_to_keep.includes(key) && value !== undefined
)
)
);
console.log(result)
How can I recursively add a sort key to an infinite hierarchy like this:
[
{
"id": "D41F4D3D-EA9C-4A38-A504-4415086EFFF8",
"name": "A",
"parent_id": null,
"sortNr": 1,
"children": [
{
"id": "07E556EE-F66F-49B5-B5E4-54AFC6A4DD9F",
"name": "A-C",
"parent_id": "D41F4D3D-EA9C-4A38-A504-4415086EFFF8",
"sortNr": 3,
"children": []
},
{
"id": "8C63981E-0D30-4244-94BE-658BAAF40EF3",
"name": "A-A",
"parent_id": "D41F4D3D-EA9C-4A38-A504-4415086EFFF8",
"sortNr": 1,
"children": [
{
"id": "0BA32F23-A2CD-4488-8868-40AD5E0D3F09",
"name": "A-A-A",
"parent_id": "8C63981E-0D30-4244-94BE-658BAAF40EF3",
"sortNr": 1,
"children": []
}
]
},
{
"id": "17A07D6E-462F-4983-B308-7D0F6ADC5328",
"name": "A-B",
"parent_id": "D41F4D3D-EA9C-4A38-A504-4415086EFFF8",
"sortNr": 2,
"children": []
}
]
},
{
"id": "64535599-13F1-474C-98D0-67337562A621",
"name": "B",
"parent_id": null,
"sortNr": 2,
"children": []
},
{
"id": "1CE38295-B933-4457-BBAB-F1B4A4AFC828",
"name": "C",
"parent_id": null,
"sortNr": 3,
"children": [
{
"id": "D1E02274-33AA-476E-BA31-A4E60438C23F",
"name": "C-A",
"parent_id": "1CE38295-B933-4457-BBAB-F1B4A4AFC828",
"sortNr": 1,
"children": [
{
"id": "76A8259C-650D-482B-91CE-D69D379EB759",
"name": "C-A-A",
"parent_id": "D1E02274-33AA-476E-BA31-A4E60438C23F",
"sortNr": 1,
"children": []
}
]
}
]
}
]
I want to get a sortable index.
For example 0000.0001.0003 or 0001.0003 for node A-C.
The function for leadingZeroes is
function fillZeroes (num) {
var result = ('0000'+num).slice(-4);
if (num===null){
return result
} else {
return '0000';
}
}
It should be sorted by sort number in each level of hierarchy, the sort number should be set newly every time, because I want to do rearrangement by setting it 1,5 to insert it between 1 and 2 (later for drag and drop capability). so 1;1,5;2 should become 1;2;3 and can then be translated to a sort-index like above.
I will also need it for indentation and breadcrumb-stuff.
How do I insert the proper sort-index to each object ?
The question is mainly about the recursion part. I am quite new to JavaScript
Thanks a lot
Based on great answer by #georg. A bit adjusted solution based on sortNr object property.
You can run it straight as is with json being your object. The sort index is written into sortOrder property.
// Mutates the given object in-place.
// Assigns sortOrder property to each nested object
const indexJson = (json) => {
const obj = {children: json};
const format = (xs) => xs.map(x => pad(x, 4)).join('.');
const pad = (x, w) => (10 ** w + x).toString().slice(-w);
const renumber = (obj, path) => {
obj.path = path;
obj.sortOrder = format(path);
obj.children.slice()
.sort((obj1, obj2) => obj1.sortNr - obj2.sortNr)
.forEach((c, n) => renumber(c, path.concat(n+1)));
};
renumber(obj, []);
};
indexJson(json);
console.log(JSON.stringify(json, null, 2));
Basically
let renumber = (obj, path) => {
obj.path = path
obj.children.forEach((c, n) => renumber(c, path.concat(n)))
}
renumber({children: yourData}, [])
this creates a path property, which is an array of relative numbers. If you want to format it in a special way, then you can do
obj.path = format(path)
where format is like
let format = xs => xs.map(pad(4)).join(',')
let pad = w => x => (10 ** w + x).toString().slice(-w)