Display image in table column if image_id equals order_id - javascript

I have two arrays of objects. I would like to match order id and image item_id and display an image for order into table column.
I tried forEach over both and setState with image filename, but it only gave me one picture. Is there any other way how to accomplish this. I'm using functional based component in React.
Thanks
// orders array of object
let orders = [
{id: 1, heading: "ddd", description: "ddd", user_created: "Joe"},
{id: 2, heading: "eee", description: "eee", user_created: "Mike"}
]
// images array of object
let images = [
{item_id: 1, filename: "nat-2-large.jpg"},
{item_id: 2, filename: "nat-3-large.jpg"},
]
// comparison
const [filenameForPath, setFilenameForPath] = useState('');
const getFilePath = () => {
ordersArr.forEach(order => {
files.forEach((file) => {
if(order.id == file.item_id){
console.log("success");
setFilenameForPath(file.filename);
}
});
});
}
useEffect(() => {
getFilePath();
},[]);

Here, at the bottom variable mapped is your result.
let orders = [
{id: 1, heading: "ddd", description: "ddd", user_created: "Joe"},
{id: 2, heading: "eee", description: "eee", user_created: "Mike"}
]
// images array of object
let images = [
{item_id: 1, filename: "nat-2-large.jpg"},
{item_id: 2, filename: "nat-3-large.jpg"},
]
const mapped = orders.reduce((arr, item, index)=> {
let res;
images.forEach((file) => {
if(file.item_id === item.id) {
res = {...item, ...file};
}
})
return [...arr, res]
}, [])
console.log(mapped)

If you are sure the number of items will be equal in both and ids will be unique, you can do something like
let result = orders.map((order,index) => order.id === images[index].item_id ? images[index] : null)

Related

Form into a single array after iterating an object

How to get values of views into single array and get the two largest values in that array. The below is not creating single array. Could someone please advise ?
const data = [
{
id: 1,
views: 5678,
textData: "Sun"
},
{
id: 2,
views: 2500,
textData: "Moon"
},
{
id: 3,
views: 3500,
textData: "Earth"
},
{
id: 4,
views: 1250,
textData: "Sky"
}
]
data.map(({id, views, textData}) =>{
let myArr = [];
myArr.push(views);
let result = Math.max(...myArr);
console.log(result);
})
Desired Array: [5678, 2500, 3500, 1250 ]
Final Output : [5678,3500 ]
You can use Array#map to create an array of the views properties, then sort it.
const data=[{id:1,views:5678,textData:"Sun"},{id:2,views:2500,textData:"Moon"},{id:3,views:3500,textData:"Earth"},{id:4,views:1250,textData:"Sky"}];
let res = data.map(x => x.views).sort((a,b) => b - a).slice(0, 2);
console.log(res);
Get result in one loop without sorting, but the code doesn't look very clean.
const data=[{id:1,views:5678,textData:"Sun"},{id:2,views:2500,textData:"Moon"},{id:3,views:3500,textData:"Earth"},{id:4,views:1250,textData:"Sky"}];
const values1 = []
const values2 = [0, 0]
data.forEach(d => {
values1.push(d.views)
values2[0] = Math.max(values2[0], Math.min(d.views, values2[1]))
values2[1] = Math.max(d.views, values2[1])
})
console.log('single values: ', values1)
console.log('two largest values: ', values2)

ES6 extract array filtering array of object with array of id

I need to extract from carriers the code of the items present in active array:
const carriers = [
{ id: 0, code: "gls" },
{ id: 1, code: "tnt" },
{ id: 2, code: "fedex" },
{ id: 3, code: "ups" },
{ id: 4, code: "postnl" },
];
const active = [0, 2, 3];
const active_code = [];
let result = carriers.filter((c) => active.includes(Number(c.id)));
console.log(result);
result.forEach((item) => {
active_code.push(item.code);
});
console.log(active_code);
Expected result:
["gls", "fedex", "ups"]
The above code works, but I'd like to learn if there's a better/easier/more elegant way to get the same result?
Thanks
As a starter a tweak can be done by mapping it instead of creating a blank array and pushing to it.
carriers.filter(i=>active.includes(+i.id)).map(i=>i.code)
Map the active array by .finding the associated carrier.
const carriers = [
{"id":0,"code":"gls"},
{"id":1,"code":"tnt"},
{"id":2,"code":"fedex"},
{"id":3,"code":"ups"},
{"id":4,"code":"postnl"}
];
const active = [0,2,3];
const result = active.map(id => carriers.find(c => c.id === id).code);
console.log(result);
For less computational complexity, turn the carriers into a structure indexed by ID first.
const carriers = [
{"id":0,"code":"gls"},
{"id":1,"code":"tnt"},
{"id":2,"code":"fedex"},
{"id":3,"code":"ups"},
{"id":4,"code":"postnl"}
];
const active = [0,2,3];
const carriersById = Object.fromEntries(
carriers.map(c => [c.id, c])
);
const result = active.map(id => carriersById[id].code);
console.log(result);
1) You can achieve the result using Map.
const carriers = [
{ id: 0, code: "gls" },
{ id: 1, code: "tnt" },
{ id: 2, code: "fedex" },
{ id: 3, code: "ups" },
{ id: 4, code: "postnl" },
];
const active = [0, 2, 3];
const map = new Map(carriers.map(({ id, code }) => [id, code]));
const active_code = active.map((id) => map.get(id));
console.log(active_code);
2) You can also get the result using Set
const carriers = [
{ id: 0, code: "gls" },
{ id: 1, code: "tnt" },
{ id: 2, code: "fedex" },
{ id: 3, code: "ups" },
{ id: 4, code: "postnl" },
];
const active = [0, 2, 3];
const set = new Set(active);
const active_code = carriers
.filter((o) => set.has(o.id))
.map(({ code }) => code);
console.log(active_code);
I would map the carriers data to active_code directly.
You could also create an active_ids object to avoid calling includes for every entry.
const carriers = [
{ "id": 0, "code": "gls" },
{ "id": 1, "code": "tnt" },
{ "id": 2, "code": "fedex" },
{ "id": 3, "code": "ups" },
{ "id": 4, "code": "postnl" }
];
const active = [0, 2, 3];
const active_ids = Object.fromEntries(active.map(i => [i, true]));
let active_code = carriers
//.filter(c => active.includes(c.id))
.filter(c => active_ids[c.id]) // faster if many items?
.map(c => c.code)
console.log(active_code);
// expected ["gls", "fedex", "ups"]
console.assert(active_code[0] === "gls")
console.assert(active_code[1] === "fedex")
console.assert(active_code[2] === "ups")

Retain array structure when filtering nested array

My brain froze with this advanced filtering. This task has exceeded my basic knowledge of filter, map etc.
Here I have an array with nested objects with array:
const DATA = [
{
title: 'Spongebob',
data: [
{ id: 1, name: 'Mr Crabs' },
{ id: 2, name: 'Sandy' }
]
},
{
title: 'Dragon Balls Z',
data: [
{ id: 1, name: 'GoKu' },
{ id: 2, name: 'Zamasu' }
]
}
];
You may have seen this sort of style if you've worked with React Native (RN). This question is not for RN. I need to perform a filter on the name property in the nested array and when I get a match, I must return the format as the DATA variable.
const handleFiltering = (value) => {
const _value = value.toLowerCase();
const results = DATA.map(o => {
return o.data.filter(o => o.name.toLowerCase().indexOf(_value) != -1)
});
console.log(results);
};
My limited knowledge of deep filtering returns the basic filtering for the data array but need to retain the structure for DATA. The expected results I'd expect:
// I'm now querying for "ZAMASU"
const handleFiltering = (value='ZAMA') => {
const _value = value.toLowerCase();
const results = DATA.map(o => {
return o.data.filter(o => o.name.toLowerCase().indexOf(_value) != -1)
});
// console.log(results) should now be
// [
// {
// title: 'Dragon Balls Z',
// data: [
// { id: 2, name: 'Zamasu' }
// ]
// }
// ];
};
What comes to mind is the use of {...DATA, something-here } but my brain has frozen as I need to get back the title property. How to achieve this, please?
Another solution would be first use filter to find only objects containing the name in data passed through the argument, subsequently mapping data.
Here is your adjusted filter method
const handleFiltering = (value) => {
const _value = value.toLowerCase();
const results = DATA.filter((obj) =>
obj.data.some((character) => character.name.toLowerCase() === _value)
).map((obj) => ({
title: obj.title,
data: obj.data.filter(
(character) => character.name.toLowerCase() === _value
),
}));
console.log(results);
};
You can use reduce method of array. First find out the object inside data array and then add that to accumulator array as new entry by preserving the original structure.
const DATA = [
{
title: 'Spongebob',
data: [
{ id: 1, name: 'Mr Crabs', where: 'tv' },
{ id: 2, name: 'Sandy' }
]
},
{
title: 'Dragon Balls Z',
data: [
{ id: 1, name: 'GoKu' },
{ id: 2, name: 'Zamasu' }
]
}
];
let handleFiltering = (value='tv') => {
return DATA.reduce((acc,d) => {
let obj = d.data.find(a => a.name?.toLowerCase().includes(value.toLowerCase())
|| a.where?.toLowerCase().includes(value.toLowerCase()));
obj ? acc.push({...d, data:[obj]}) : null;
return acc;
}, []);
}
let result = handleFiltering();
console.log(result);

array.push didn't push object based on sequence while some object do action with await

I'm trying to loop my object with map, inside the map I need to do action with sequelize so I use async and Promise.all to support async, but it give me result that the object sequence is not like the original sequence, the sequence start with data that doesn't do action with sequelize.
For example:
const data = await Student.findAll({
limit: 2,
where: {
level: 'Primary 1'
},
order: [['id', 'ASC']]
}).then(async resultStudent => {
// [{"id": 1, "name": "Alex", "gender": "Male", "level": "Primary 1"}, {"id": 2, "name": "Betty", "gender": "Female", "level": "Primary 1"}]
let finalData = [];
await Promise.all(
resultStudent.map(async (e, index) => {
let studentHobbies;
if(e.gender == 'Male'){
studentHobbies = await Hobbies.findOne({
where: {
studentID: e.id
}
})
}
let obj = {
id: e.id,
hobby: studentHobbies ? studentHobbies.hobbyName : null
};
finalData.push(obj);
})
)
})
The code above give me result as:
[{
"id": 2,
"hobby": null
}, {
"id": 1,
"hobby": "Playing Guitar, and Basketball"
}]
While my expected result was:
[{
"id": 1,
"hobby": "Playing Guitar, and Basketball"
}, {
"id": 2,
"hobby": null
}]
Try using map with async callback to keep the order:
const data = await Student.findAll({
limit: 2,
where: {
level: 'Primary 1'
},
order: [['id', 'ASC']]
}).then(resultStudent => Promise.all(
resultStudent.map(async student => ({
id: student.id,
hobby: (student.gender === 'Male')
? await Hobbies.findOne({ where: { studentID: student.id } })
: null
})
)))
Edit: easier to read version
const data = await Student.findAll({ // array of ordered results from query
limit: 2,
where: {
level: 'Primary 1'
},
order: [['id', 'ASC']]
}).then(results =>
results.map(async ({ id, gender }) => ({ // array of promises that run asynchronously and resolve with formatted objects
id,
hobby: (gender === 'Male')
? await Hobbies.findOne({ where: { studentID: id } })
: null
}))
).then(Promise.all) // array of results of resolved promises, in same order. resolves when all have completed
Each of the three arrays is wrapped in a promise. const data = await extracts the final result from the end of the promise chain.
Your code is almost correct. What you need to change is the following. Instead of initializing the finalData array outside of the map-loop and pushing to it inside the map-function you should use the array that the map function returns and return the data object at the end of the map-function.
Also, you can simplify your code-flow by taking advantage of the nature of async/await and remove the then callback.
This should provide you the data in the right order:
// Change: No need to use the then-callback, when you are using await here
const resultStudent = await Student.findAll({
limit: 2,
where: {
level: 'Primary 1'
},
order: [
['id', 'ASC']
]
})
// Change: Rely on map to return the data in the same order as it was passed in
const finalData = await Promise.all(
resultStudent.map(async (e, index) => {
let studentHobbies;
if (e.gender == 'Male') {
studentHobbies = await Hobbies.findOne({
where: {
studentID: e.id
}
})
}
let obj = {
id: e.id,
hobby: studentHobbies ? studentHobbies.hobbyName : null
};
// Change: Return data from map function
return obj;
})
)
// finalResult will have the same array order as resultSudent here
I hope this helps.
According to the docs, the map() function already returns an array.
Try to modify your code to set finalData like so:
finalData = resultStudent.map(async (e, index) => {
and delete following line:
finalData.push(obj);
Important: the declaration let finalData = []; needs to remain 'as is'
Could you please try this one?
const data = await Student.findAll({
limit: 2,
where: {
level: 'Primary 1'
},
order: [['id', 'ASC']]
})
const finalData = await Promise.all(
data.map( async (e, index) => {
let studentHobbies;
if(e.gender == 'Male'){
studentHobbies = await Hobbies.findOne({
where: {
studentID: e.id
}
})
}
const obj = {
id: e.id,
hobby: studentHobbies ? studentHobbies.hobbyName : null
};
return Promise.resolve( obj )
})
)
if it works I'll give further explanations

How to remove child by id and retrive the parent objects using filter

I am trying to filter the parent, by removing it's child id only by not matching. in case if there is no child exist, the parent should be removed.
I try like this, but not works.
var rm = 7;
var objects = [
{
name: "parent1",
id: 1,
blog: [
{
name: "child1",
id: 1
},
{
name: "child2",
id: 2
}
]
},
{
name: "parent2",
id: 2,
blog: [
{
name: "child3",
id: 3
},
{
name: "child4",
id: 4
}
]
},
{
name: "parent3",
id: 3,
blog: [
{
name: "child5",
id: 5
},
{
name: "child6",
id: 6
}
]
},
{
name: "parent4",
id: 3,
blog: [
{
name: "child6",
id: 7
}
]
},
]
var result = objects.filter(value => {
if(!value.blog) return;
return value.blog.some(blog => blog.id !== rm)
})
console.log(result);
What is wrong here, or some one show me the correct approach?
looking for :
need to remove the blog if the id is same as rm, parent with other children required to exist.
need to remove the parent, after remove the children, in case there is no child(blog) exist.
Live Demo
Loop through the list of parents, and inside that loop, try to remove blogs with the given id first. Once you have done that, you can check if the blogs property has became empty, and if so, filter it out:
// We're going to filter out objects with no blogs
var result = objects.filter(value => {
// First filter blogs that match the given id
value.blog = value.blog.filter(blog => blog.id !== rm);
// Then, if the new length is different than 0, keep the parent
return value.blog.length;
})
I think the below code is what you are looking for
var result = objects.map(value => {
const blog = value.blog.filter(blog => blog.id !== rm);
if(blog.length === 0) {
return;
}
value.blog = blog;
return value;
}).filter(item => item);
Demo: https://jsfiddle.net/7Lp82z4k/3/
var result = objects.map(parent => {
parent.blog = parent.blog.filter(child => child.id !== rm);
return parent}).filter(parent => parent.blog && parent.blog.length > 0);

Categories