How to check if specific values of Object items in Array - javascript

My goal: I want to modify this Array (See; Current Array with Objects) to only main properties where one or more (items) is greater than 0. In this example, the current Array should be modified by removing all object named: tags and sale_status from the Array, since there are no items is higher than 0 with count. So you only keep the Object over quotation_status.
How can I handle this the right way? I've tried various ways of looping, but can't figure it out.
Current Array with Objects
[{
"id": "tags",
"label": "Tags",
"items": [{
"key": 2,
"count": 0
}, {
"key": 1,
"count": 0
}, {
"key": 3,
"count": 0
}]
}, {
"id": "sale_status",
"label": "Status",
"items": [{
"key": "completed",
"count": 0
}, {
"key": "processing",
"count": 0
}, {
"key": "on-hold",
"count": 0
}]
}, {
"id": "quotation_status",
"label": "Status",
"items": [{
"key": "concept",
"count": 1
}]
}]
Desired output:
[{
"id": "quotation_status",
"label": "Status",
"items": [{
"key": "concept",
"count": 1
}]
}]
Current Script
function activeFilters() {
let test = test1.value
let filters = store.getters[test].filters
const result = filters.filter((o) => o.items.some((obj) => obj.count));
return result;
};

You can use filter and some to get the desired result
arr.filter((o) => o.items.some((obj) => obj.count))
const arr = [
{
id: "tags",
label: "Tags",
items: [
{
key: 2,
count: 0,
},
{
key: 1,
count: 0,
},
{
key: 3,
count: 0,
},
],
},
{
id: "sale_status",
label: "Status",
items: [
{
key: "completed",
count: 0,
},
{
key: "processing",
count: 0,
},
{
key: "on-hold",
count: 0,
},
],
},
{
id: "quotation_status",
label: "Status",
items: [
{
key: "concept",
count: 1,
},
],
},
];
const result = arr.filter((o) => o.items.some((obj) => obj.count));
console.log(result);

Related

How can I return an array of values from an array of grouped objects in js?

I have an array of subscriptions group by the type (basic,medium ...)
`
[
[
"Basic",
[
{ "id": 2, "name": "Basic", "started_at": "2022-01-24", "count": 4 },
{ "id": 2, "name": "Basic", "started_at": "2022-03-16", "count": 2 },
{ "id": 2, "name": "Basic", "started_at": "2022-05-16", "count": 1 }
]
],
[
"Medium",
[
{ "id": 3, "name": "Medium", "started_at": "2022-02-21", "count": 1 },
{ "id": 3, "name": "Medium", "started_at": "2022-05-28", "count": 1 }
]
],
[
"Premium",
[{ "id": 4, "name": "Premium", "started_at": "2022-04-21", "count": 1 }]
],
[
"Master",
[
{ "id": 7, "name": "Master", "started_at": "2022-07-28", "count": 1 },
{ "id": 7, "name": "Master", "started_at": "2022-08-02", "count": 1 }
]
],
[
"Jedi",
[{ "id": 6, "name": "Jedi", "started_at": "2022-09-28", "count": 1 }]
]
]
`
What I want to do is return an array containing objects foreach sub with the following data(get the count value by month):
`
[
{
label: "Basic",
data: [4, 0, 2, 0, 1,0],
},
{
label: "Medium",
data: [0, 1, 0, 0, 1,0],
},
...
]
`
The data field should contain the count field foreach subscription corresponding to the month. For example for with count 4 in January and count 2 in March it will return [4,0,1] with 0 for February.
How can I achieve that ?
I did this but it's returning only the existing month values so there is no way to know which month that value is for.
subscriptions.map((item) => {
return {
label: item[0],
data: item[1].map((value, index) => {
return value.count;
}),
};
})
You could reduce the array and create a mapper object which maps each plan with month specifc count. Something like this:
{
"Basic": {
"1": 4,
"3": 2,
"5": 1
},
"Medium": {
"2": 1,
"5": 1
},
...
}
Then loop through the entries of the object and create objects with plan as label and an array of length: 12 and get the data for that specific month using the index
const input=[["Basic",[{id:2,name:"Basic",started_at:"2022-01-24",count:4},{id:2,name:"Basic",started_at:"2022-03-16",count:2},{id:2,name:"Basic",started_at:"2022-05-16",count:1}]],["Medium",[{id:3,name:"Medium",started_at:"2022-02-21",count:1},{id:3,name:"Medium",started_at:"2022-05-28",count:1}]],["Premium",[{id:4,name:"Premium",started_at:"2022-04-21",count:1}]],["Master",[{id:7,name:"Master",started_at:"2022-07-28",count:1},{id:7,name:"Master",started_at:"2022-08-02",count:1}]],["Jedi",[{id:6,name:"Jedi",started_at:"2022-09-28",count:1}]]];
const mapper = input.reduce((acc, [plan, subscriptions]) => {
acc[plan] ??= {}
for(const { started_at, count } of subscriptions)
acc[plan][+started_at.slice(5,7)] = count
return acc;
}, {})
const output =
Object.entries(mapper)
.map( ([label, subData]) => ({
label,
data: Array.from({ length: 12 }, (_, i) => subData[i+1] ?? 0)
}) )
console.log(output)
Note:
This assumes that the data is for a single year only. If it can be across years you'd have to create another level of nesting:
{
"Basic": {
"2022": {
"1": 3
}
}
}
started_at.slice(5,7) is used to get the month number. If the dates are not in the ISO 8601 format, you can use new Date(started_at).getMonth() + 1 to get the month part.

How to find the value by find() and map()

I would like to obtain the value of name using the code below.
When find(z => z.key.value === 123) be added to the code ,there will be this error :
x.obj.array_1.find(...).find is not a function
What's wrong with this code :
const data = [{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "123"
}
}]
}]
}]
},
"name": "obj1"
},
{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "456"
}
}]
}]
}]
},
"name": "obj2"
},
{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "789"
}
}]
}]
}]
},
"name": "obj3"
}
]
const name = data
.filter(x =>
x.obj.array_1.find(y => y.array_2).find(y => y.array_3).find(z => z.key.value === 123)
).map(x => x.name);
console.log(name)
Small fix here, this work provided that your real life data is also in this shape
After finding the propriate array_1 element that have array2[0] which has non-nil array_3, you have to access that array_3 to iterate and find the expected value
Edited (because array_2 and array_3 may have multiple elements): you have to extract all array_3 element (using flatMap to flatten the nested array) and do the condition check from that extracted array
const name = data
.filter((x) => {
const flattened_array_3 = x.obj.array_1.flatMap((array_1_el) =>
array_1_el.array_2.flatMap((array_2_el) => array_2_el.array_3)
)
return flattened_array_3.find((array_3_el) => +array_3_el.key.value === 123)
})
.map((x) => x.name)
Full code
const data = [
{
obj: {
array_1: [
{
array_2: [
{
array_3: [
{
key: {
value: "123",
},
},
],
},
],
},
],
},
name: "obj1",
},
{
obj: {
array_1: [
{
array_2: [
{
array_3: [
{
key: {
value: "456",
},
},
],
},
],
},
],
},
name: "obj2",
},
{
obj: {
array_1: [
{
array_2: [
{
array_3: [
{
key: {
value: "789",
},
},
],
},
],
},
],
},
name: "obj3",
},
]
const name = data
.filter((x) => {
const flattened_array_3 = x.obj.array_1.flatMap((array_1_el) =>
array_1_el.array_2.flatMap((array_2_el) => array_2_el.array_3)
)
return flattened_array_3.find((array_3_el) => +array_3_el.key.value === 123)
})
.map((x) => x.name)
console.log(name)
Reference: flatMap
x.obj.array_1.find(y => y.array_2)
is undefined.
Try to split your code
In order to work on this structure, I advise you to change the way you represent data.
It seems like some kind of output of tokenization. There have to bee tools to extract information from the path for example XPath, etc.
On the other hand below code should work for your case
The key point is using flatMap to rest inner arrays to upper one
const data = [{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "123"
}
}]
}]
}]
},
"name": "obj1"
},
{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "456"
}
}]
}]
}]
},
"name": "obj2"
},
{
"obj": {
"array_1": [{
"array_2": [{
"array_3": [{
"key": {
"value": "789"
}
}]
}]
}]
},
"name": "obj3"
}
]
var obj = data.find(x=> x.obj.array_1.flatMap(x=>x.array_2).flatMap(x=>x.array_3)[0].key.value==789)
console.log(obj.name)

How to order an array of objects in array of categories in javascript?

I have the following array of objects
{
"nome": "jose",
"categoria": [
{ "id": "1" },
{ "id": "3" },
]
},
{
"nome": "maria",
"categoria": [
{ "id": "2" },
]
},
{
"nome": "pedro",
"categoria": [
{ "id": "1" },
]
}
I have to reorder in another array of categories. Something like this:
{
"id": "1",
"pessoas": [
{
"nome": "jose",
"categoria": [
{ "id": "1" },
{ "id": "3" },
]
},
{
"nome": "pedro",
"categoria": [
{ "id": "1" },
]
},
]
},
{
"id": "2",
"pessoas": [
{
"nome": "maria",
"categoria": [
{ "id": "2" }
]
},
]
},
I have try with the function reduce(), but I couldn't because it is not an object, but a array of objects (categoria)
const group = data.reduce((r, array) => {
r[array.categoria.id] = [...r[array.categoria.id] || [], array];
return r;
}, {});
Someone can help me please?
You could take an object for grouping by id. Inside of reduce, categoria is iterated as well for getting the needed id.
var data = [{ nome: "jose", categoria: [{ id: "1" }, { id: "3" }] }, { nome: "maria", categoria: [{ id: "2" }] }, { nome: "pedro", categoria: [{ id: "1" }] }],
result = Object.values(data.reduce((r, o) => {
o.categoria.forEach(({ id }) => {
if (!r[id]) r[id] = { id, pessoas: [] };
r[id].pessoas.push(o);
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Find the parent of the searched value using javascript

I have a JSON data in the following format which needs to be filtered based on a specific value :
[
{
"id": 0,
"name": "ROOT-0",
"childs": [
{
"id": 1,
"name": "ROOT-1",
"childs": [
{
"id": 11,
"name": "ROOT-11",
},
{
"id": 12,
"name": "ROOT-12",
},
]
},
{
"id": 2,
"name": "ROOT-2",
"childs": [
{
"id": 21,
"name": "ROOT-21",
},
{
"id": 22,
"name": "ROOT-22",
},
]
},
{
"id": 3,
"name": "ROOT-3",
"childs": [
{
"id": 31,
"name": "ROOT-31",
},
{
"id": 32,
"name": "ROOT-32",
},
]
}
]
}]
The scenario is that I need to get ROOT-1 as final result if I look for ROOT-11/ROOT-12.
I have tried filtering with this following code
var res = data[0].filter(function f(o) {
if (o.name.includes("ROOT-11")) return o;
})
But I am not able to get a grip on the logic. Is there a way to achieve my desired output
You could use find()...
var result = data[0].childs.find(x => {
return x.childs.find(y => {
return y.name === name;
});
}).name;
Or you could write a function...
function findParentName(name, data) {
return data[0].childs.find(x => {
return x.childs.find(y => {
return y.name === name;
});
}).name;
}
var result = findParentName('ROOT-11', data);
console.log(result);
Doing this will give you the best performance result as find() will return as soon as it finds a match, and not iterate through each remaining loop like forEach() or map()
If you're using ES6 you can say...
const result = data[0].childs.find(x => x.childs.find(y => y.name === 'ROOT-11')).name;
You can grab the item using a few filters and a find, to get the result you are looking for:
let items = [{
"id": 0,
"name": "ROOT-0",
"childs": [{
"id": 1,
"name": "ROOT-1",
"childs": [{
"id": 11,
"name": "ROOT-11",
},
{
"id": 12,
"name": "ROOT-12",
},
]
},
{
"id": 2,
"name": "ROOT-2",
"childs": [{
"id": 21,
"name": "ROOT-21",
},
{
"id": 22,
"name": "ROOT-22",
},
]
},
{
"id": 3,
"name": "ROOT-3",
"childs": [{
"id": 31,
"name": "ROOT-31",
},
{
"id": 32,
"name": "ROOT-32",
},
]
}
]
}]
function find(name) {
let result
items.filter(item =>
result = item.childs.find(item2 =>
item2.childs.filter(i => i.name == name).length > 0
)
)
return result.name || ''
}
console.log(find('ROOT-11'))
console.log(find('ROOT-22'))
console.log(find('ROOT-32'))
You could, for an arbitrary count nested children, use a recusion approach by iterating the actual level and if not found check the children with the actual name.
If the wanted name is found, the parent's name is handed over through all nested calls and returned.
function getParent(array, search, parent) {
return array.some(o => o.name === search || o.children && (parent = getParent(o.children, search, o.name)))
&& parent;
}
var data = [{ id: 0, name: "ROOT-0", children: [{ id: 1, name: "ROOT-1", children: [{ id: 11, name: "ROOT-11" }, { id: 12, name: "ROOT-12" }] }, { id: 2, name: "ROOT-2", children: [{ id: 21, name: "ROOT-21" }, { id: 22, name: "ROOT-22" }] }, { id: 3, name: "ROOT-3", children: [{ id: 31, name: "ROOT-31" }, { id: 32, name: "ROOT-32" }] }] }]
console.log(getParent(data, 'ROOT-0')); // undefined no parent found
console.log(getParent(data, 'ROOT-1')); // ROOT-0
console.log(getParent(data, 'ROOT-11')); // ROOT-1
console.log(getParent(data, 'ROOT-31')); // ROOT-3
.as-console-wrapper { max-height: 100% !important; top: 0; }

lodash merge and combine objects

I have an array of objects as below that I read from my database using sequelize ORM:
I want to have all my videos from a section, but the better I can return using sequelize is :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
}
},
{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}
}]
Is there a way to merge and combine the objects in my array to obtain something like this :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": [{
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
},{
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}]
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": [{
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
},{
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}]
}
The function that approach the most is _.mergeWith(object, sources, customizer) but the main problem I have is that I have on object and need to merge this object.
In plain Javascript, you can use Array#forEach() with a temporary object for the arrays.
var data = [{ id: 2, name: "Ru", subsection: 1, Video: { id: 11, source: "sourrrccrsss22222", VideoSubSection: 2 } }, { id: 2, name: "Ru", subsection: 1, Video: { id: 12, source: "sourrrccrsss111", VideoSubSection: 2 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 13, source: "sourrrcc", VideoSubSection: 1 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 14, source: "sourrrcc", VideoSubSection: 1 } }],
merged = function (data) {
var r = [], o = {};
data.forEach(function (a) {
if (!(a.id in o)) {
o[a.id] = [];
r.push({ id: a.id, name: a.name, subsection: a.subsection, Video: o[a.id] });
}
o[a.id].push(a.Video);
});
return r;
}(data);
document.write('<pre>' + JSON.stringify(merged, 0, 4) + '</pre>');
Maybe try transform():
_.transform(data, (result, item) => {
let found;
if ((found = _.find(result, { id: item.id }))) {
found.Video.push(item.Video);
} else {
result.push(_.defaults({ Video: [ item.Video ] }, item));
}
}, []);
Using reduce() would work here as well, but transform() is less verbose.
You can do it this way (test is your db output here)
var result = [];
var map = [];
_.forEach(test, (o) => {
var temp = _.clone(o);
delete o.Video;
if (!_.some(map, o)) {
result.push(_.extend(o, {Video: [temp.Video]}));
map.push(o);
} else {
var index = _.findIndex(map, o);
result[index].Video.push(temp.Video);
}
});
console.log(result); // outputs what you want.

Categories

Resources