Merge Data from different Queries without duplicates - javascript

I am getting data from three different queries via Api. I want data to be merged without the duplicate data.
This is my function where i am merging the data:
getStaffCount(data) {
if (data == null || data.results === null )
return [];
else
return data.results.StaffCount.map(m => ({ Name: m.Name, Accounts: m.Accounts })).
concat(data.results.RepProviderAccount.map(m => ({ Name: m.Name, Accnt: m.Accnt }))).
concat( data.results.ProviderAccount.map(m => ({ Name: m.Name, Account: m.Account })));
}
This is my table:
<PowerTable Data={{ rows: this.getStaffCount(this.props.GridData) }} rowsPerPage={5} orderBy="Name" order="asc" >
<PowerColumn id='Name' columnName='Name' numeric={false} disablePadding={false} label='Profile Name' width={100}>
</PowerColumn>
<PowerColumn id='Accounts' columnName='Accounts' numeric={false} disablePadding={false} label='Staff Accounts' width={100}>
</PowerColumn>
<PowerColumn id='Account' columnName='Account' numeric={false} disablePadding={false} label='Provider Account' width={100} >
</PowerColumn>
<PowerColumn id='Accnt' columnName='Accnt' numeric={false} disablePadding={false} label='Rep Provider Account' width={100} >
</PowerColumn>
</PowerTable>
So in the above image same Profile Name(CNX MSL Platform) is coming twice. So is there any way i can merged those rows?
I want the Output in this way:
Profile Name Staff Provider Rep Provider
Cnx MSl Platform 2 1
Cnx Specilaity sales Platform 7 22
Data:

As an object
if the data is an object the easy way to do that is the spread opperator
const combinedData = {
...dataSrc1,
...dataSrc2,
...dataSrc3,
}
All matching keys will be overwritten by the previous
As an array
It's a bit more complex. Assuming your object has a unique id (or any value to identify 2 as the same item) you can use a Set since they can only have unique values.
const array = [
...dataSrc1,
...dataSrc2,
...dataSrc3,
]
const unique = [...new Set(array.map(item => item.id))];

Your answer to my question about what the data looks like and how to group them didn't make any sense, neither did you answer Joe just showed the json data and tell him where the data comes from instead of what it is.
So I assume you group by Name and Account is ignored. You can group them in the following way:
const data = {
results: {
StaffCount: [
{
Name: 'a',
Accounts: 2,
},
{
Name: 'b',
Accounts: 20,
},
],
RepProviderAccount: [
{
Name: 'a',
Accnt: 3,
},
],
ProviderAccount: [
{
Name: 'a',
Account: 1,
},
],
},
};
const grouped = [
...data.results.StaffCount,
...data.results.RepProviderAccount,
...data.results.ProviderAccount,
].reduce((result, item) => {
const {
Name,
Account = 0,
Accounts = 0,
Accnt = 0,
} = item;
const existing = result.get(item.Name) || {
Name,
Account: 0,
Accounts: 0,
Accnt: 0,
};
existing.Account += Account;
existing.Accounts += Accounts;
existing.Accnt += Accnt;
return result.set(Name, existing);
}, new Map());
console.log([...grouped.values()]);
In case this doesn't work for you can you please update your question and provide code as in my answer with the expected input and output? You can respond to this answer and I'll have a look at your question again.
This may actually be an xy problem, you are fetching 3 data sources and then trying to group and sum them but maybe you can just get 1 data source and try salesforce to group and sum them in the query. I don't know enough about salesforce but maybe you can ask another question tagging it with soql if it's possible to just get the data grouped and summed.

Related

fetch object within object

I am trying to fetch NAME which is in SKILLS.
For that I use filter for initial level sorting.Means I am able to sort rows but how do I fetch name?
let r = this.topics.filter(a => {
console.log('a is : ', a)
return a.Skills.name
})
I think you are misunderstanding what Array.filter does, it filters out/removes items from the array that does not match the criteria the user passes it, more about it here filter docs
In this case you use a Array.map to transform the data, more about it heremap docs.
let r = this.topics.map(item => {
return item.skills.map( skill => skill.name)
})
The above code will return something like [['Writing', 'Reading'], ['Testing', 'Debugging']]
You can use Map and Sort functions to achieve this.
const topics = [{
Skills: [{
name: "Java",
id: 1
},
{
name: "C++",
id: 2
},
{
name: "Python",
id: 3
}
]
}]
let r = topics.map((a) => {
return a.Skills.sort((a, b) => {
return a.name.localeCompare(b.name);
});
});
console.log(r);

Get values from objects in array with rest parameter

let newValues = user.info.socialMedia ? [...user.info.socialMedia] : []
So here we get several objects into the array that have an id key, and instead of the objects themselves I want to have only the id strings in this array. How can I get this working? I am quite new to Javascript, so it would be nice to get some help here.
I tried a for of then a for in loop to get the ids out of there and push them to the array, tho this does not work for my case.
instead of the objects themselves I want to have only the id strings
That sounds like a .map() operation, to project one array into another by applying a transformation to each object. Something like this:
let newValues = user.info.socialMedia ? user.info.socialMedia.map(s => s.id) : []
Or perhaps simpler:
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
For example:
let user = {
info: {
socialMedia: [
{ id: 1, name: 'Ron' },
{ id: 2, name: 'Tammy' },
{ id: 3, name: 'Tammy 2' }
]
}
};
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
console.log(newValues);

Filtering data after fetching in React

I need to make a list of objects based on combined data from 2 arrays, one comes from a localStorage and the second one from Django backend. First of all objects from localStorage are displayed by showCart() function
export const showCart = () => {
if (typeof window !== undefined) {
if (localStorage.getItem("cart")) {
return JSON.parse(localStorage.getItem("cart"));
};
};
};
it returns data in this format: FE: { id: 1, amount: 7, size: "L", product: 1 }. product is the Foreign Key needed to match data from other array.
The second array comes form a backend and it is feched by getAllProducts() function
export const getAllProducts = () => {
return fetch(`${url}/products/`, {method: "GET"})
.then((response) => {
return response.json();
})
.catch((error) => console.log(error))
};
It returns data in this format: FE { name: "Red", id: 3, price: 33, image:"some-url"}
​​
Now I need to create another list of objects by merging then by product of an object in first array with id of an object from the second one. The objects in the third array need to contain amount and size from first array as well as name, price and image from the second one. In the end I want to store it in useState().
This is what I came up with, I guess my code stops working arter first for loop:
const [cart, setCart] = useState([]);
const CheckAnonymousCart = () => {
getAllProducts()
.then((data) => {
const localCart = showCart();
var products = [];
for (let i = 0; i < localCart.lenght; i++) {
for (let y = 0; y < data.lenght; y++) {
if (localCart[i].product === data[y].id) {
console.log(localCart[i].product, data[y].id)
const item = {
name: data[y].name,
price: data[y].price,
image: data[y].image,
amount: localCart[i].amount,
size: localCart[i].size,
}
products.push(item)
break;
}
}
}
setCart(products);
})
.catch((error) => console.log(error))
};
​​Any thoughts?
In addition to Jacob's comment, you probably want to avoid FETCH'ing all products from the DB, because it requires more DB resources, most of the info is not required, and it makes the for-loop take longer to JOIN both lists.
Ideally, you would use a parameterized query like so:
return fetch(`${url}/products/?id=1&id=2&id=3`, {method: "GET"})
Where ?id=1&id=2&id=3 are a subset of the product IDs that you're retrieving.
Note: You will also want to sanitize/validate the product IDs in localStorage, because the data can be modified by the end-user, which is a potential attack vector by malicious users.
The problem could simply be the typo from the for loop conditions, but you can also accomplish this more succinctly using the JS ES6 methods:
const products = localCart.map(item => {
const match = data.find(x => x.id === item.product);
return {
amount,
size,
name: match?.name,
price: match?.price,
image: match?.image
}
});

javascript find() in nested array

I'm trying to build a website with REACT. In the homepage you have 2 buttons, europe and usa.
Let's say you click europe. Then you see a list of all the countries in europe.
And when you click a country, you should see a list of CITIES in that country.
The question is, how can I access the items inside "cities"?.
const DATA = [
{
id: 1,
title: "EUROPE",
countries: [
{
id: 1,
country: "france",
cities: [
{
id: 1,
city: "paris"
},
{
id: 2,
city: "toulouse"
}
];
// so at homepage, you click "europe", and on the second page i got this:
const StateCard = () => {
const { title } = useParams();
const selectedData = DATA.find( d => d.title === title);
return(
<div className="main">
{selectedData &&
selectedData.countries.map((item, id) => {
return (
<div className="card-container" >
<Link key={id} to={`${title}/${item.country}`}> {item.country} </Link>
</div>
);
})}
</div>
useParams gives us back the title that added to the URL after the first click,
which is "europe".
selectedData gives us back the items inside "europe":
{id: 1, title: "EUROPE", countries: Array(1)}
and now the screen shows "france". you clicked france, and now i wanna show the 2 cities inside.
all i got is:
const { country } = useParams();
which gives us "france".
but i dont know how to access the cities inside.
i tried to play with DATA.countries.find(), but whatever i put after DATA. gives me
"TypeError: Cannot read property 'find' of undefined".
sorry its so long thanks guys!
Each type (continents, countries, cities) is an array. find won't work on DATA.countries because countries is a property of whatever continent object you select.
It may help you to divide up your data collections using a series of methods. getContinents gets the data as an argument, and the value of title. getCountries receives the array returned by getContinents - as well as the value of country - and returns its own array of countries, and then getCities maps over that data to return the city names.
This way you maintain a series of data collections, and the code is easier to maintain.
const data = [{"id":1,"title":"EUROPE","countries":[{"id":1,"country":"france","cities":[{"id":1,"city":"paris"},{"id":2,"city":"toulouse"}]}]}];
const title = 'EUROPE';
const country = 'france';
const getContinents = (data, val) => data.find(obj => obj.title === title)
const getCountries = (data, val) => data.countries.find(obj => obj.country === val)
const getCities = (data) => data.cities.map(obj => obj.city);
// Pass in the data and the value of title
const continents = getContinents(data, title);
// Use the array returned from `getContinents` and the country value
const countries = getCountries(continents, country);
// Use the array returned from `getCountries`
const cities = getCities(countries);
console.log(cities);
You can first find the Country and then on countriesResult you can find citiesResult and then can find cities from citiesResult.cities.
You're getting the error **TypeError: Cannot read property 'find' of undefined** because
what you're doing is DATA.countries.find(). Data is an array so you can't use .countries on it. You have to find the country using find or use index.
const DATA = [{
id: 1,
title: "EUROPE",
countries: [{
id: 1,
country: "france",
cities: [{
id: 1,
city: "paris",
},
{
id: 2,
city: "toulouse",
},
],
}, ],
}, ];
const title = "EUROPE";
const country = "france";
const countriesResult = DATA.find((d) => d.title === title);
const citiesResult = countriesResult.countries.find(
(c) => c.country === country
);
const result = citiesResult.cities.map((c) => c.city);
console.log(result);
DATA is an array of objects. Each item in DATA have countries array. So, you have to use find() on specific item in DATA array, and not on DATA array iteself. For example, you can do this:
DATA[0].countries.find()

How can loop through array of JSON Object to find property value that includes user input characters

What is the correct method JavaScript function I can use to loop through an array of JSON data and return the JSON.KEY value that includes the user input query
Suppose that we have an array books with these data
const books = [
{ title: 'chemistry', pages: 123 },
{ title: 'chemical abcd', pages: 103 },
{ title: 'anatomy of something ', pages: 423 }
];
When a user query is
let query= 'chemi'
Then the output should be
filteredBooks = [
{ title: 'chemistry', pages: 123 },
{ title: 'chemical abcd', pages: 103 }
];
For this I would use the js Array.filter method:
const filteredBooks = books.filter(book => book.title.includes(query))
In addition of the other questions, using destructuring saves a bit of code:
const filteredBooks = books.filter(({title}) => title.includes(query));
this method searches all the values of the object if they contain the query. you should make your query lowercase first:
query=query.toLowerCase();
filteredBooks = books.filter(book=>Object.values(book).some(value=>value.toString().toLowerCase().includes(query)));
if the book object has sub-fields, this is a lazy way to query them:
query=query.toLowerCase();
filteredBooks = books.filter(book=>JSON.stringify(Object.values(book)).toLowerCase().includes(query))

Categories