Merging by id correctly but get empty object - Javascript - javascript

I have two arrays that needs to be merged by id (sourceID), which seems to be done, but both imagesTest objects return empty. Now sure what I am doing wrong here?
My code looks like this:
const eventsToBeInserted1 = [{
name: 'Katy Perry',
slug: 'katy-perry',
sourceID: [1],
tags: ['music', 'jazz'],
images1: ['picture_perry_1', 'picture_perry_2']
},
{
name: 'Lukas Graham',
slug: 'lukas-graham',
sourceID: [2],
tags: ['rock', 'techno'],
images1: ['picture_graham_1', 'picture_graham_2']
}
]
const imagesTest = [{
sourceID: 1,
images: ['picture_perry.jpg']
},
{
sourceID: 2,
images: ['picture_graham.jpg']
}
]
const eventsToBeInserted = eventsToBeInserted1.map(
event => Object.assign({}, event, {
imagesTest: imagesTest
.filter(img => img.sourceID === event.sourceID)
.map(img => img.name)
}))
console.log(eventsToBeInserted)

The problem is that in eventsToBeInserted1 the sourceId is defined as an array: sourceID: [1].
Either change it to be defined as a regular int: sourceID: 1
or change the merge function:
const eventsToBeInserted = eventsToBeInserted1.map(
event => Object.assign({}, event, {
imagesTest: imagesTest
.filter(img => img.sourceID === event.sourceID[0])
.map(img => img.name)
}))

Related

Filtered object search using allowed keys and also a search value

as seen in my title I am facing a problem that needs a solution. I am trying to filter my object, but not only based on keys. But also based on the value of the allowed keys.
This is what I got so far:
const handleSearch = (searchValue) => {
if(searchValue !== '') {
const allowed = ['name', 'title'];
let list = props.search.list;
const filtered = Object.keys(list)
.filter((key) => allowed.includes(key))
.reduce((obj, key) => {
obj[key] = list[key];
return obj;
}, {});
const filteredArray = Object.entries(filtered)
props.search.onChange(filteredArray)
} else {
props.search.onChange(props.search.list)
}
}
Structure of the list object:
0: {name: "John', title: 'Owner'}
1: {name: "Jane", title: 'Admin'}
Wanted results:
Filtered array that shows the keys filtered aswell as the search value.
And I don't know where I should integrate the filtering by the values aswell. This has been giving me a headache for the past few hours. And hope someone here is experienced with these kinds of issues/logic.
Thanks for reading.
Kind regards.
const handleSearch = (searchValue) => {
if (searchValue !== '') {
const allowed = ['name', 'title'];
const list = props.search.list;
const filtered = list
.filter(obj =>
Object.keys(obj)
.some(k => allowed.includes(k))
)
.filter(obj =>
Object.values(obj)
.map(v => v.toLocaleLowerCase())
.some(v => v.includes(searchValue.toLowerCase()))
)
props.search.onChange(filtered)
} else {
props.search.onChange(props.search.list)
}
}
Example
Let's assume props as:
const props = {
search: {
list: [
{ name: "John", title: 'Owner' },
{ name: "Jane", title: 'Admin' },
{ name: "Reza", title: 'Owner' }
],
onChange: x => console.log(x)
},
}
handleSearch("own")
// [ { name: 'John', title: 'Owner' }, { name: 'Reza', title: 'Owner' } ]
handleSearch("jane")
// [ { name: 'Jane', title: 'Admin' } ]
handleSearch("something")
// []

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

Pushing values into an object of array

So I have an array of objects called products:
const products = [
{
name: 'Pants'
},
{
name: 'Shoes'
},
{
name: 't shirts'
}
]
And the list contains a lot more products with other values apart from name. So suppose i forgot to give each product, (object) a coupon's array, it would take me quite a while to update each object manually.
Is there a function that I can create which will push a coupons value into each object as an array?
So the final array would look like:
const updatedProducts = [
{
name: 'Pants',
coupons: []
},
{
name: 'Shoes',
coupons: []
},
{
name: 't shirts',
coupons: []
}
]
const updatedProducts = products.map(product => ({ ...product, coupons: [] }))
Yes you can add properties in javascript like this:
products.forEach(product => product.coupons = []);

How to sort an array of objects in the same order as an id array

I have an array of players objects like this :
var players = [{
id: "thisIsID1",
name: "William",
otherProps
},
{
id: "thisIsID2",
name: "Shakespeare",
otherProps
},
{
id: "thisIsID3",
name: "Lola",
otherProps
}]
And I have and array of their ID that has been shuffled, like so :
var shuffledIDs = ["thisIsID2", "thisIsID3", "thisIsID1"]
How can I sort the players var so the objects are in the same order as the corresponding IDs of shuffledIDs ?
Edit: different names just for the sake of making players different
If your data is short, then you can sort it with the following one-liner:
players = shuffledIDs.map(id => players.find(v => v.id == id))
Essentially, for every id in shuffledID, it finds the element in players with that id and puts it in the correct spot. However, this takes O(n^2) time so it might not scale well for larger data. If you want a faster method, you can maintain an object of IDs:
var ids = {};
players.forEach(v => ids[v.id] = v);
players = shuffledIDs.map(v => ids[v]);
You can achieve it using array .find() method:
var players = [{
id: "thisIsID1",
name: "William"
},
{
id: "thisIsID2",
name: "Shakespeare"
},
{
id: "thisIsID3",
name: "Lola"
}]
var shuffledIDs = ["thisIsID2", "thisIsID3", "thisIsID1"]
var result = shuffledIDs.map(x => players.find(p=>p.id === x))
console.log(result)
Create object with keys and values as index from shuffle array.
Use sort method and prioritize bases above shuffled indexes. This way should even the case of duplicate data in players.
var players = [
{
id: "thisIsID1",
name: "William"
},
{
id: "thisIsID2",
name: "Shakespeare"
},
{
id: "thisIsID3",
name: "Lola"
}
];
const shuffleIds = ["thisIsID2", "thisIsID3", "thisIsID1"];
const shuf_idx = Object.fromEntries(shuffleIds.map((x, i) => [x, i]));
players.sort((a, b) => shuf_idx[a.id] - shuf_idx[b.id]);
console.log(players);
With .map() and .find() where using index of the element:
const shuffledIDs = ["thisIsID2", "thisIsID3", "thisIsID1"];
const players = [{ id: "thisIsID1", name: "William" }, { id: "thisIsID2", name: "Shakespeare" }, { id: "thisIsID3", name: "Lola" }];
const result = players.map((e, i) => players.find(f => f.id === shuffledIDs[i]));
console.log(result);

Filter string and null values from object

when a value of a property of the object is null or contains "missing" the whole object should be filterd.
this works for filtering null
object = (object.filter(o => !Object.values(o).includes(null))
But how can I add 2 filters and how to implement a filter that filters strings that contain the word "missing"
object = (object.filter(o => !Object.values(o).includes(null) | ("missing")));
object:
[
{ id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
}
{ id: 'qtum',
name: 'Qtum',
image:
'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
]
Use Array.prototype.every().
Use && to combine multiple tests.
let object = [{
id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
},
{
id: 'qtum',
name: 'Qtum',
image: 'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
];
console.log(object.filter(o => Object.values(o).every(prop =>
prop != null && !prop.toString().includes("missing"))));
Use && and match
const object = [
{id: 'blockstack-iou',
name: 'Blockstack (IOU)',
image: 'missing_large.png'
},
{ id: 'qtum',
name: 'Qtum',
image:
'https://assets.coingecko.com/coins/images/684/large/qtum.png?1547034438',
price_change_percentage: -53.2869774915231
}
]
const filtered = (object.filter(o =>!Object.values(o).includes(null) && !Object.values(o).toString().match(/missing/gi)));
console.log(filtered)
If you're looking for a solution that is easily extensible, consider storing all your "conditions" as an array and running through them using .every().
const object = [
{str: "this_is_missing"},
{str: null},
{str: "valid"}
];
const validations = [
i => i !== null, //Value isn't null
i => !i.toString().includes("missing") //Value doesn't contain "missing"
];
const validate = (val) => validations.every(fn => fn(val));
const result = object.filter(obj => Object.values(obj).every(validate));
console.log(result);

Categories