Javascript array is not somehow mutated - javascript

I have an express server which I have GET and POST, and as original state, I have the following:
let orders = [
{
sum: 0,
purchases: [
{
id: 1,
contractId: 55,
value: 100,
},
{
id: 2,
contractId: 55,
value: -100,
}
]
}
]
// this function is running on GET request
export const getOrders = (req, res) => {
reply.status(200).send(orders)
}
export const addOrder = (req, res) => {
const newOrder = req.body
orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
My intention here is to search in the list of orders if the new added order ID is exist, if so, then add it to the list of corresponding purchases, otherwise, create a new object containing a sum and the new order, but whenever I try to add a new order with the same id then it add it to the found contractID PLUS creating a new object containing a sum and new order.
here is an example of what I get after my first POST and then GET:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
}
]
then my second attempts of adding a different order with POST:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
}
]
}
]
then another post and got this results:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 200,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
},
{
"id": 4,
"contractId": 44,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 4,
"contractId": 44,
"value": 100
}
]
}
]
any idea why this weird behavior is happening?

This is because orders.map returns a new object and doesn't mutate the original, you can override the original with:
orders = orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
But honestly, I don't recommend mutating Objects in this context, because more than 1 request can be reading/writing that variable.
If you really need to use this approach, use Array.forEach and reference the original object instead of map (that returns a new array and doesn't mutate the original one)

Related

Can't loop array after grouping with .reduce

I've got the following meetings object :
[
{
"id": 19,
"duration": 1.75,
"Employee": {
"name": "Jeanne",
}
},
{
"id": 20,
"duration": 1.00,
"Employee": {
"name": "Louis",
}
},
{
"id": 21,
"duration": 1.00,
"Employee": {
"name": "Jeanne",
}
}
]
I want to group it by Employee.name. Using reduce() here is what I come up with :
meetings.reduce(function (r, a) {
r[a.Employee.name] = r[a.Employee.name] || [];
r[a.Employee.name].push(a);
return r;
}
The resulting object is the following :
{
"Jeanne": [
{
"id": 19,
"duration": 1.75,
"Employee": {
"name": "Jeanne"
}
},
{
"id": 21,
"duration": 1.00,
"Employee": {
"name": "Jeanne"
}
}
],
"Louis": [
{
"id": 20,
"duration": 1.00,
"Employee": {
"name": "Louis"
}
}
]
}
If I try to map() or forEach() i cannot get the value of the element :
Array.from(thisMeeting).forEach(element => console.log(element));
return `undefined`;
Array.from-ming an Object will result in an empty array.
You'll have to iterate over the objects keys with Object.entries(thisMeeting).forEach… and grab the values inside that.

Is there any way to filter objects from array of objects that should include all selected values in javascript

Here i have skills array and employees array and i am trying to get the employees that includes all the skills that are included in skills array using reduce, filter or find method. I am trying to stored the filtered employees in filteredItems but got stuck in it.
filteredItems = Skills?.length>0 ?
Employees?.filter((item) => {
return item.Skills.find((ele) => {
return Skills.find((el) => {
if(el.value === ele.id){
return ele
}
})
})
}) : []
Below are the arrays mentioned.
Skills Array
[
{
"value": 6,
"label": "Marketing"
},
{
"value": 20,
"label": "Golang"
}
]
Employees Array
[
{
"name": "Hassan",
"id": 56,
"Skills": [
{
"id": 20,
"name": "Golang",
},
],
},
{
"name": "Haroon",
"id": 95,
"Skills": [
{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
},
]
For example, in above scenario of arrays it should return employee of id of 95 not return employee of id 56 because it includes skills but not all that are mention in skills array.
I found it easier to first encapsulate an array of skill IDs to search for.
let skillIds = Skills.map(s => s.value);
Then I filtered and compared the end result to the length of the skill Ids array:
let filteredItems = Skills?.length > 0 ?
Employees?.filter(item => item.Skills.filter( s =>
skillIds.includes(s.id)).length==skillIds.length): []
let Skills = [{
"value": 6,
"label": "Marketing"
}, {
"value": 20,
"label": "Golang"
}]
let Employees = [{
"name": "Hassan",
"id": 56,
"Skills": [{
"id": 20,
"name": "Golang",
}],
}, {
"name": "Haroon",
"id": 95,
"Skills": [{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
}, ]
let skillIds = Skills.map(s => s.value);
let filteredItems = Skills?.length > 0 ?
Employees?.filter(item => item.Skills.filter( s => skillIds.includes(s.id)).length==skillIds.length): []
console.log(filteredItems)
You could create another property in the employees array.. call it "QUalified". Default it to true, then set it to false when the employee doesn't have a skill in the skills array.
let arSkills = [
{
"value": 6,
"label": "Marketing"
},
{
"value": 20,
"label": "Golang"
}
];
let arEmp = [
{
"name": "Hassan",
"id": 56,
"Skills": [
{
"id": 20,
"name": "Golang",
},
],
},
{
"name": "Haroon",
"id": 95,
"Skills": [
{
"id": 6,
"name": "Marketing",
},
{
"id": 20,
"name": "Golang",
},
],
},
];
arEmp.forEach(ele =>{
ele.Qualified = true;
let arTmp = [];
for(let {id} of ele.Skills)
arTmp.push(id)
for(let {value} of arSkills)
if(!arTmp.includes(value))
ele.Qualified = false
});
let arQual = arEmp.filter((ele) =>{
return ele.Qualified
});
console.log(arQual);

How to get immediate parent Id of the child id in array of nested json Object?

I need to get the parent id of the specific child.
Here is my sample JSON, If I give entity id 32 it should return 6 as parent Id and if I give 30 it should return 5 as parent id.
const arr = [{
"id": 0,
"name": "My Entity",
"children": [
{
"id": 1,
"name": "MARKET",
"children": [
{
"id": 2,
"name": "Sales",
"children": [
{
"id": 3,
"name": "District 1",
"children": [
{
"id": 5,
"name": "Area 1",
"children": [
{
"entityId": 30,
"id": 26,
"name": "Mumbai"
},
{
"entityId": 31,
"id": 26,
"name": "Hyderabad"
}
],
"num": 0,
},
{
"id": 6,
"name": "Area 2",
"children": [
{
"entityId": 32,
"id": 32,
"name": "Karnataka"
},
{
"entityId": 33,
"id": 33,
"name": "Andhra Pradesh"
}
],
"num": 0,
},
]
},
]
},
]
},
]
}]
Here is the code I have tried
const findParent = (arr, entityId) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].entityId === entityId) {
return [];
} else if (arr[i].children && arr[i].children.length) {
const t = findParents(arr[i].children, entityId);
if (t !== false) {
t.push(arr[i].id);
return t;
}
}
}
return false;
};
findParents(arr, 30);
But it is returning like below
[
5,
3,
2,
1,
0
]
But I want the output to be
[
5
]
Kindly help me on this, thanks
Replace this:
t.push(arr[i].id);
with:
if (t.length == 0) t.push(arr[i].id);
I would suggest easier solution
const findParent = (arr, entityId) => {
const children = arr.flatMap(parent =>
(item.children || []).map(child => ({ parent, child, entityId: child.entityId }))
)
const res = children.find(item => item.entityId === entityId)
return res.entityId || findChildren(res.map(v => v.child), entityId)
}

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

Need to match object values from one array to the object values from another array

In the following code. I am trying to get the id of a variant that matches the selected objects
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant() {
return variants.filter( options => {
// return id 3 because it matches the selected objects
});
}
console.log(filterVaiant());
The filter function should return variant id:3 because it has the same option values as the selected option values.
follow up
const colors = require('colors');
const selected = [ { "id": 14 }, { "id": 95 }, { "id": 21 } ]
let selected_ids = selected.map(e=>e.id);
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
},
{
"id": 4,
"option_values": [ { "id": 14 }, { "id": 95, }, { "id": 21 } ]
}
]
let vID = variants.filter(e=> e.option_values.every(e=> selected_ids.indexOf(e.id) > -1));
console.log("answer:",vID) // Returns 3 and 4 but should only return 4
in this scenario vID is 3 and 4 but should only return 4 because it is the only one that matches the selections exactly.
You can use .filter and .every to achieve this like
const selected = [ { "id": 14 }, { "id": 95 } ];
var ids = selected.map(e=>e.id);
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
];
var o = variants.filter(e=> e.option_values.every(e=> ids.indexOf(e.id) > -1));
console.log(o)
What's happening here is, get all the selected ids in an array, then filter the variants array based on if every entry of option_values has all the entries as the selected ids.
For each object, check that all items in selected appear in option_values (ops alias) by checking that the length is equal, and using Array.every(), and Array.find():
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [{"id":1,"option_values":[{"id":7},{"id":95}]},{"id":2,"option_values":[{"id":8},{"id":95}]},{"id":3,"option_values":[{"id":14},{"id":95}]}];
function filterVaiant() {
return variants.filter(({ option_values: ops }) => {
if (selected.length !== ops.length) return false;
return selected.every(({ id }) =>
ops.find((o) => id === o.id));
});
}
console.log(filterVaiant());
Using a Set to store the selected Id's to look up and Array#every in a filter
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant(selected) {
let ids = new Set(selected.map(({id})=>id))
return variants.filter( o => o.option_values.every(({id})=>ids.has(id)));
}
console.log(filterVaiant(selected));
Another solution with map only indexof and join:
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant(selected) {
return variants[variants.map(obj => obj.option_values).map(outterarray => outterarray.map(innerArray=>innerArray.id).join('-') ).indexOf(selected.map(eb=>eb.id).join('-'))];
}
console.log(filterVaiant(selected));

Categories

Resources