create a schema from a nodejs response - javascript

OilĂ , if possible I wanted some suggestions on how I could fix this. I get this from a nodejs request:
..data: 0:{id:1, image:"image1.jpg"}
1:{id:1, image:"image2.jpg"}
2:{id:1, image:"image3.jpg"}
3:{id:3, image:"image4.jpg"}
4:{id:3, image:"image5.jpg"}
5:{id:3, image:"image6.jpg"}
6:{id:3, image:"image7.jpg"}
7:{id:5, image:"image8.jpg"}
8:{id:5, image:"image9.jpg"}
9:{id:5, image:"image10.jpg"}
10:{id:5, image:"image11.jpg"}
11:{id:5, image:"image12.jpg"}
I would like to create a schema similar to the json that allows me to group the images by their respective id, for example:
{
"id": 1,
"images": ["image1.jpg","image2.jpg",..]
}
{
"id": 3,
"images": ["image4.jpg","image5.jpg",..]
},
{
"id": 5,
"images": ["image8.jpg","image9.jpg",..]
}
If anyone could give me some help or suggestions on how to do it, I would be very grateful

Did you try using reduce & Map to group the images by Id . Something like this -
const result = Array.from(data.reduce((map, {id, image}) =>
map.set(id, [...(map.get(id) || []), image]), new Map())
).map(([id, images]) => ({id, images}));

You can use the built-in JavaScript Array.reduce() method to group the images by their respective id.
The syntax for Array.reduce() is as follows:
arr.reduce(callback[, initialValue])
The callback function takes two parameters:
accumulator - The accumulator accumulates the callback's return values; it is the accumulated value previously returned in the last invocation of the callback, or initialValue, if supplied.
currentValue - The current element being processed in the array.
So, in your case, you can use the following code:
const data = [
{id:1, image:"image1.jpg"},
{id:1, image:"image2.jpg"},
{id:1, image:"image3.jpg"},
{id:3, image:"image4.jpg"},
{id:3, image:"image5.jpg"},
{id:3, image:"image6.jpg"},
{id:5, image:"image8.jpg"},
{id:5, image:"image9.jpg"},
{id:5, image:"image10.jpg"},
{id:5, image:"image11.jpg"},
{id:5, image:"image12.jpg"}
];
const result = data.reduce((acc, curr) => {
const {id, image} = curr;
if (!acc[id]) {
acc[id] = {id, images: []};
}
acc[id].images.push(image);
return acc;
}, {});
console.log(result);
Output will be:
// output
// {
// "1": {
// "id": 1,
// "images": [
// "image1.jpg",
// "image2.jpg",
// "image3.jpg"
// ]
// },
// "3": {
// "id": 3,
// "images": [
// "image4.jpg",
// "image5.jpg",
// "image6.jpg"
// ]
// },
// "5": {
// "id": 5,
// "images": [
// "image8.jpg",
// "image9.jpg",
// "image10.jpg",
// "image11.jpg",
// "image12.jpg"
// ]
// }
// }

Related

How to map or assign an entry to an array-item based on some of this item's conditions?

I have array of objects,
if the name is xx then push xitems to that object and
if the name is yy then push yitems to that object
Below is the code tried , and also should not use spread operator
const result = [];
var ss=arrobj.forEach(function(e){
if(e.name === 'xx'){
result.push({id: e.id, name: e.name, country:e.country, others: xitems})
}
if(e.name === 'yy'){
result.push({id: e.id, name: e.name, country:e.country, others: yitems})
}
return result;
});
var arrobj =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
]
xitems =[
{title: "Finance", valid: true}
]
yitems =[
{title: "Sales", valid: true}
]
Expected Output
[
{id:1, name: "xx", country: "IN",
others:[
{title: "Finance", valid: true}
]
},
{id:2, name: "yy", country: "MY",
others: [
{title: "Sales", valid: true}
]
},
]
You should use .map for this.
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj.map((item) => {
if (item.name === "xx") {
item.others = xitems;
} else if (item.name === "yy") {
item.others = yitems;
}
return item;
});
console.log(result);
Your code works, the only issue that I identified are.
There is no need to assign var ss with arrobj.forEach. Because Array.forEach donot return a value.
No need of return result; inside Array.forEach.
Also as an improvement you can simply assign the object with key others like Object.assign({}, e, { others: xitems }), rather than returning individual key value.
Working Fiddle
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
]
const xitems = [
{ title: "Finance", valid: true }
]
const yitems = [
{ title: "Sales", valid: true }
]
const result = [];
arrobj.forEach(function (e) {
if (e.name === 'xx') {
result.push(Object.assign({}, e, { others: xitems }))
}
if (e.name === 'yy') {
result.push(Object.assign({}, e, { others: yitems }))
}
});
console.log(result)
Variables are references to an object that has a value, variables do not store values. It is pointless to try to use a variable in that manner unless you have specific parameters. If you insist on a condition then you need to identify xitems and yitems by the objects values and/or properties or by the order they came in. If you have dynamic data how would you know what xitems or yitems really is?
The example below has been made reusable as long as you meet these requirements:
Must have an array of objects as a primary parameter.
Must have at least one array of objects for each object in the primary array. If there's more the rest will be ignored.
The secondary array of objects must be in the order you want then to end up as.
The second parameter is a rest parameter (not a spread operator, although I have no idea why OP does not want to use it). This will allow us to stuff in as many object arrays as we want.
const distOther = (main, ...oAs) => {...
Next we create an array of pairs from all of the secondary arrays
let others = oAs.map(sub => ['others', sub]);
// [['others', [{...}]], [['others', [{...}]], ...]
Then we turn our attention to the primary array. We'll work our way from the inside out. .map() each object as an array of pairs by Object.entries():
main.map((obj, idx) =>
// ...
Object.entries(obj)
// ...
// [{A: 1, B: 2}, {...}] => [[['A', 1], ['B', 2]], [[...], [...]]]
Then .concat() (a spead operator would be more succinct) each array of pairs with that of the secondary array of pairs corresponding to the current index (you'll need to wrap each secondary array in another array, so the return will level off correctly):
// main.map((obj, idx) =>
// ...
// Object.entries(obj)
.concat([others[idx]])));
// [[['A', 1], ['B', 2], ['others', [{...}]], [[...], [...], ['others', [{...}]]]
Finally we'll use Object.fromEntries() to convert each array of pairs into an object.
// main.map((obj, idx) =>
Object.fromEntries(
// Object.entries(obj)
// .concat([others[idx]])));
// [{'A': 1, 'B': 2, 'others': [{...}]},...]
const objArr =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
];
const x =[
{title: "Finance", valid: true}
]
const y =[
{title: "Sales", valid: true}
]
const distOther = (main, ...oAs) => {
let others = oAs.map(sub => ['others', sub]);
return main.map((obj, idx) =>
Object.fromEntries(
Object.entries(obj)
.concat([others[idx]])));
};
console.log(distOther(objArr, x, y));
I would choose a map based approach as well but without the if clauses which explicitly check for expected values of the mapped item's name property.
The approach instead utilizes map's 2nd thisArg parameter which gets applied as the mapper functions this context. Such an additional object can be provided as a map/index of custom key value pairs where key equals a mapped item's name.
Thus the mapper implementation features generic code, and due to the this binding it will be provided as function statement which makes it also re-usable and, if properly named, readable / comprehensible / maintainable too.
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item,
{ others: index[item.name] ?? [] },
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
As one can see, the above implementation via Object.assign creates a new object from each mapped arrobj item. Thus the original item-references remains untouched / non mutated. It does not apply for the items of xitems and yitems since both array references are directly assigned each to its newly created others property. The above log does reflect this.
In case the goal was an entirely reference free data structure one needs to slightly change the Object.assign part of assignBoundNamedValueAsOthers ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item, {
others: (index[item.name] ?? [])
// dereference the `others` items as well.
.map(othersItem =>
Object.assign({}, othersItem)
)
},
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
In case the OP does not need to care about immutability, the entire process then changes from a map task to a forEach task, where assignBoundNamedValueAsOthers does directly change/mutate each currently processed item of arrobj, thus forEach does not return any data but always the undefined value ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// mutate the original reference of the currently
// processed `item` by directly assigning, according
// to `item.name`, the bound named value as `others`.
Object.assign(
item,
{ others: index[item.name] ?? [] },
);
// no explicit return value due to
// going to be used as a `forEach` task.
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
// mutates each item of `arrobj`.
arrobj.forEach(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }

Check if ID Is Found Another Array in ES6

I wanted to filter out the data. I wanted to check if data on data1 is found on data2 and to check if it has errorMessages. Please check my code below. Is there a better way to do it?
data1
[
{
"ids": "0111",
},
{
"ids": "0222",
},
{
"ids": "0333",
}
]
data2
[
{
"id": "0111",
"errorMessages": [
{
"message": ["sample error message 1"]
}
]
},
{
"id": "0333",
"errorMessages": []
}
]
Code
const output= data1.filter(
(element) => element.ids === data2.find((data) => data).id
);
console.log("output", output);
.find((data) => data) doesn't do anything useful - each item in the array is an object, which is truthy, so that'll always return the first element in the array.
If you did want to .find a matching element in the other array - then a better approach would be to make a Set of the IDs found in the other array first (Set lookup is much quicker - O(1) - than .find, which is O(n)).
You also need to implement the logic to check if the errorMessages is empty.
const data1 = [
{
"ids": "0111",
},
{
"ids": "0222",
},
{
"ids": "0333",
}
]
const data2 = [
{
"id": "0111",
"errorMessages": [
{
"message": ["sample error message 1"]
}
]
},
{
"id": "0333",
"errorMessages": []
}
]
const ids = new Set(
data2
.filter(item => item?.errorMessages.length)
.map(item => item.id)
);
const output= data1.filter(
element => ids.has(element.ids)
);
console.log("output", output);
Without Set, but use Object as the map.
const IDKeys = {};
data2.forEach(data => {
if (data.errorMessages.length){
IDKeys[data.id] = true; // means valid
}
})
const filteredArray = data1.filter(data => IDKeys[data.id]);
This would be only O(n) since accessing key on object is O(1)

JavaScript modify Array of Objects and alter contained data

I am having difficulties formatting some data. Currently, I receive data in the following structure.
[
{
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
}
]
I essentially need to modify this or even create a new object, that takes the following structure.
[
{
id: 1, //q1
answers: [
{
answer: '5',
},
],
},
{
id: 2, //q2
answers: [
{
answer: '13',
},
{
answer: '12',
},
],
},
{
id: 3, //q3
answers: [
{
answer: 'test',
},
],
},
];
So the id in the above would be obtained by remove the q and getting the number in the first data object. It would then have an answers array that would have an object for each answer.
I have been attempting this but have gotten lost. I don't know if I should use loops, mapping, filters etc. To be honest, the furthest I have got so far is obtaining the keys
var modified = data.map(function(item) {
return Object.keys(item)
})
I have created a JSFiddle where I have been attempting to do this.
Is there any way I can achieve the data I am after?
Many thanks
Please use map function.
const data = {
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
};
const result = Object.keys(data).map(key => {
let item = {id: key.substring(1), answers: []};
if(typeof data[key] === "string")
item.answers.push({answer: data[key]});
else
item.answers = data[key].map(val => ({answer: val}));
return item;
});
console.log(result)
const inputData = [
{
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
}
]
function answerMapper(objVal, id){
return Array.isArray(objVal)
?
{ id, answers: objVal.map(answer => ({ answer }))}
:
{ id, answers: [{answer: objVal }] }
}
function formatObject(obj){
return Object.keys(obj).map((k, i) => answerMapper(obj[k], i+1));
}
const result = inputData.map(obj => formatObject(obj));
// remove flatMap if your inputData has more than one entry
console.log(result.flatMap(x => x));
map over the first element of the data with Object.entries, grab the key and value, create a new answers array and return a new object.
const data = [{
"q1": "5",
"q2": [
"13",
"12",
],
"q3": "test",
}];
const out = Object.entries(data[0]).map(obj => {
const [ key, value ] = obj;
const id = Number(key[1]);
// If the the value is an array
// return a new array of mapped data
// Otherwise return an array containing
// one object
const answers = Array.isArray(value)
? value.map(el => ({ answer: el }))
: [{ answer: value }];
// Return the new object
return { id, answers };
});
console.log(out);
lets create a pure function which accepts the object in the array like so
const processObject = obj => Object.keys(obj).map(id => {
const answer = obj[id];
const answers = Array.isArray(answer) ? answer : [answer]
const answerObjectArray = answers.map(ans => ({
answer: ans
}));
return {
id: +id.substring(1),
answers: answerObjectArray
}
});
const dataArray = [{
"q1": "5",
"q2": [
"13",
"12",
],
"q3": "test",
}];
const output = processObject(dataArray[0]);
console.log(output);

Get Object when the array contains the input value inside nested Array of objects

Here is the nested array of object i am working on:
let arrayOfElements =
[
{
"username": "a",
"attributes":
{
roles:["Tenant-Hyd"],
groups:["InspectorIP", "InspectorFT"]
}
},
{
"username": "b",
"attributes":
{
roles:["Tenant-Pune"],
groups:["InspectorIP"]
}
},
{
"username": "c",
"attributes":
{
roles:["Tenant-Hyd"],
groups:["InspectorIP"]
}
}
];
I want users if they have Tenant-hyd role and also if groups has more then one string, then the user should be spit two.
so the final output should be:
arrayOfElements=[
{
"username": "a",
groups:"InspectorIP"
},
{
"username": "a",
groups:"InspectorFT"
},
{
"username": "c",
groups:"InspectorIP"
}
];
I would use a combination of filter and reduce array functions here.
filter would remove all elements where attributes.roles does not include 'Tenant-Hyd'.
reduce would then flatten the groups array.
const arrayOfElements =
[
{
"username": "a",
"attributes":
{
roles:["Tenant-Hyd"],
groups:["InspectorIP", "InspectorFT"]
}
},
{
"username": "b",
"attributes":
{
roles:["Tenant-Pune"],
groups:["InspectorIP"]
}
},
{
"username": "c",
"attributes":
{
roles:["Tenant-Hyd"],
groups:["InspectorIP"]
}
}
];
const filtered = arrayOfElements.filter(x => x.attributes.roles.includes('Tenant-Hyd'));
console.log('filtered', filtered);
const flattened = filtered.reduce((arr, current) => {
// create a new object for each group with the current username
const groups = current.attributes.groups.map(group => ({
username: current.username,
groups: group
}));
// push the new objects into the array
arr.push(...groups);
// return the array to the next iteration
return arr;
}, []);
console.log('flattened', flattened);
This demo sets up the initial array, runs the filter, and then runs the reduce. I have separated the steps out so you can see what's going on at each stage, but you could easily combine them.
const result = arrayOfElements
.filter(x => x.attributes.roles.includes('Tenant-Hyd'))
.reduce((arr, current) => {
arr.push(...current.attributes.groups.map(group => ({
username: current.username,
groups: group
})));
return arr;
}, []);
The reduce function
The reduce array function accepts a callback and an initial value. I am passing an empty array in as the initial value.
It is really a more powerful map. The source array will be iterated over, with the callback being called on each iteration. The value returned from the callback will be used as the accumulator on the next iteration.
// declare the callback
const callback = (arr, current) => {
// arr is the initial value on the first loop
// and whatever we return from this callback on subsequent loops
// add our flattened items to the accumulated array
arr.push(...current.attributes.groups.map(group => ({
username: current.username,
groups: group
})));
// return the accumulated array to the next iteration
return arr;
};
// loop over the items in myArray, calling the callback for each item
// pass an empty array in as the accumulator
myArray.reduce(callback, []);
A simpler alternative would be this:
const arr = [];
myArray.forEach(current => {
arr.push(...current.attributes.groups.map(group => ({
username: current.username,
groups: group
})));
});
This is easier to understand, but is not as concise as using reduce.
You can use the following snippet
let arrayOfElements = [{
"username": "a",
"attributes": {
roles: ["Tenant-Hyd"],
groups: ["InspectorIP", "InspectorFT"]
}
},
{
"username": "b",
"attributes": {
roles: ["Tenant-Pune"],
groups: ["InspectorIP"]
}
},
{
"username": "c",
"attributes": {
roles: ["Tenant-Hyd"],
groups: ["InspectorIP"]
}
}
];
var newa = [];
for (var i in arrayOfElements) {
if (arrayOfElements[i].attributes.roles[0] === 'Tenant-Hyd') {
for (var j in arrayOfElements[i].attributes.groups) {
var newObj = {
'username': arrayOfElements[i].username,
'groups': arrayOfElements[i].attributes.groups[j]
};
newa.push(newObj);
}
}
}
console.log(newa);
You can try this code
let arrayOfElements = [{
"username": "a",
"attributes": {
roles: ["Tenant-Hyd"],
groups: ["InspectorIP", "InspectorFT"]
}
},
{
"username": "b",
"attributes": {
roles: ["Tenant-Pune"],
groups: ["InspectorIP"]
}
},
{
"username": "c",
"attributes": {
roles: ["Tenant-Hyd"],
groups: ["InspectorIP"]
}
}
];
var res = [];
arrayOfElements.forEach(d => {
if (d.attributes.roles[0] == "Tenant-Hyd") {
d.attributes.groups.forEach(x => {
res.push({
"username": d.username,
"groups": x
})
})
}
});
console.log(res);

Create Multidimensional array of [key,value] with key unique count as value from Array of JSON Object

Currently i have array of json object returned by server
data: [
{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Rishi Ranabhat",
project: "ABC"
},
{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Biplap Bhattarai",
project: "DEF"
},
{
billed: "No",
designation: "SE",
involvement: "Part Time",
name: "Ram k",
project: "DEF"
},
...more json data
];
I have to create a count of values in Array like below for representation for google charts:
[
//designation count
["ASE", 2],
["SE", 2]
],
[
//project count
["ABC", 1],
["DEF", 2]
],
//and similarly others.
How can i count the no of occurances of the keys with the values of previous occurance intact,
and also in ['key','value'] of key being the unique occurance of data and value being the no of occurance ???
Iterate over the data with reduce to create an object grouped by type. Here's a reusable function - just pass in the data and the type.
const data = [{"billed":"No","designation":"ASE","involvement":"Full Time","name":"Rishi Ranabhat","project":"ABC"},{"billed":"No","designation":"ASE","involvement":"Full Time","name":"Biplap Bhattarai","project":"DEF"},{"billed":"No","designation":"SE","involvement":"Part Time","name":"Ram k","project":"DEF"}];
function getCount(data, type) {
// `map` out the data by type
const typeArr = data.map((obj) => obj[type]);
// Iterate over the type data. We pass in an initial
// object to capture the counts, so we need to use
// `Object.values` to grab the object values at the end
// of the iteration
return Object.values(typeArr.reduce((acc, id) => {
// If the key doesn't exist in the accumulator object
// create it and create a new array at its value
acc[id] = acc[id] || [id, 0];
// Increment the second index (the count)
acc[id][1]++;
// Return the object for the next iteration
return acc;
}, {}));
}
console.log(getCount(data, 'designation'));
console.log(getCount(data, 'project'));
Further reading
reduce
Object.values
Alternatively, if you wanted to do this in one operation and return an object containing the grouped information, you could use another reduce to iterate over the main data keys:
const data = [{"billed":"No","designation":"ASE","involvement":"Full Time","name":"Rishi Ranabhat","project":"ABC"},{"billed":"No","designation":"ASE","involvement":"Full Time","name":"Biplap Bhattarai","project":"DEF"},{"billed":"No","designation":"SE","involvement":"Part Time","name":"Ram k","project":"DEF"}];
function getCounts(data) {
// Grab the data keys. It assumes that each object in
// the array has the same keys
const keys = Object.keys(data[0]);
// Using `reduce` iterate over the keys to build
// up an object that groups the results from the inner
// `reduce` operation by key
return keys.reduce((out, key) => {
// `map` out the data by type
const typeArr = data.map((obj) => obj[key]);
// Iterate over the type data. We pass in an initial
// object to capture the counts, so we need to use
// `Object.values` to grab the object values at the end
// of the iteration
out[key] = Object.values(typeArr.reduce((acc, id) => {
// If the key doesn't exist in the accumulator object
// create it and create a new array at its value
acc[id] = acc[id] || [id, 0];
// Increment the second index (the count)
acc[id][1]++;
// Return the object for the next iteration
return acc;
}, {}));
// Return the `out` object for the next iteration
return out;
}, {});
}
console.log(getCounts(data));
Lot's of ways to do this. Here is a simple way (could be cleaned up, but just trying to demo):
View on JSFiddle
const data = [{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Rishi Ranabhat",
project: "ABC"
},
{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Biplap Bhattarai",
project: "DEF"
},
{
billed: "No",
designation: "SE",
involvement: "Part Time",
name: "Ram k",
project: "DEF"
}
];
const designations = [],
projects = [];
for (const record of data) {
// Count designations
if (!designations[record.designation]) {
designations[record.designation] = 0;
}
designations[record.designation] = designations[record.designation] + 1;
// Count projects
if (!projects[record.project]) {
projects[record.project] = 0;
}
projects[record.project] = projects[record.project] + 1;
}
// Merge sets
const final = [designations, projects];
console.log(final);
const data = [
{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Rishi Ranabhat",
project: "ABC"
},
{
billed: "No",
designation: "ASE",
involvement: "Full Time",
name: "Biplap Bhattarai",
project: "DEF"
},
{
billed: "No",
designation: "SE",
involvement: "Part Time",
name: "Ram k",
project: "DEF"
}
];
const result = data.reduce((acc,cur) => {
for(let k in cur) {
if(!acc[k]) {
acc[k] = [[cur[k], 1]];
} else {
const idx = acc[k].findIndex(e => e[0] === cur[k]);
if(idx !== -1) {
acc[k][idx][1]++
} else {
acc[k].push([cur[k], 1])
}
}
}
return acc;
}, {});
console.log(result)

Categories

Resources