To group of array of objects by its id value - javascript

I have a group of array of objects in which that object property has value with ID number. I am successfully group it with that ID, however I am doing it by hardcode, not dynamically.
var objBuyUser = response.newIdUserPul[i].arrayUserHistoryBuy;
for (var y = 0; y < objBuyUser.length; y++) {
if(objBuyUser[y].product_id == 1) {
var doesIdExist = vm.pulBms.filter(function(v) {
return v.userid === response.newIdUserPul[i].id;
});
if(doesIdExist.length > 0) {
//do nothhing
} else {
vm.pulBms.push({
userid:response.newIdUserPul[i].id,
buyAct: objBuyUser
});
}
}
objBuyUser[y].product_id == 1 is what will different them each other. As long as this time we only have three ID number 1, 2, 3, I just copied the same code by changing the id manually. So, anybody can help to make it dynamically?
(**)SO: actually we have the list of product: 1, 2, 3
In the backend, I have process a unique user with its history buy, assign by response.newIdUserPul[i]. And the arrayUserHistoryBuy is the array of object detailing their product history buying from the range of the date, which in the object can consiste the date, quantity, and the product_id which need to be group here (reffer to -> **). In this case, knowing that each user can buy different product in the range of date, we still group it by product since the product is exist in the history of buying.
So the output could be similar like this:
ProductID1 :
{
User: 123
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 2,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
{
User: 124
ProductBuyHistory :
{
Date: 3-10-10
ProductID : 3,
Quantity: 10
},
{
Date: 4-10-10
ProductID : 1,
Quantity: 10
},
},
SO on for productId 2 and 3

Related

Re-Map an array of Object based on sort order of a property

Let's see I have a data in following structure
[
{
"Id": "xyz7",
"CurrentRow": 0,
"ReportTime": "2022-07-18T09:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-18"
},
{
"Id": "xyz8",
"CurrentRow": 1,
"ReportTime": "2022-07-18T08:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-18"
},
{
"Id": "wxyz0",
"CurrentRow": 0,
"ReportTime": "2022-07-19T00:00:00+00:00",
"ExitTime": null,
"DateField": "2022-07-19"
},
{
"Id": "wxyz1",
"CurrentRow": 1,
"ReportTime": "2022-07-19T00:00:00+00:00",
"ExitTime": null
"DateField": "2022-07-19"
}
]
If I have to say sort the structure based on ReportTime of Date : 2022-07-18, that will change the CurrentRow of entries for DateField 2022-07-18 as
0 to 1 (as it will now belong to 1st Index) and for 2nd entry 1 - 0.
In addition, the CurrentRow of other entries (for other date shall also be adapted if they were same as that of day being sorted.)
In order to achieve this my implementation goes like,
I convert the structure to a two dimensional array based on CurrentRow.
Index in dimension 1, represents the CurrentRow.
The element of array will be an array of specific data entry like [entry_for_date_18,entry_for_date_19] (Kind of spread sheet with date as columns and CurrentRow as rows.
And then in order to sort, I pick all the entries for a particular date, sort it, and collect it with the original CurrentRow. (Pass 1).
Then I go and update the CurrentRow of original array, using the index (pass 2).
e.g pseudo code:
for(let i=0;i<sortedDayArray.length;i++){
findByInOriginalArray(sortedDayArray[i].CurrentRow).updateCurrentRowTo(i)
}
Was wondering if there is a better or more efficient way to do that, using map ?
This is how I got your question: you want to sort your array based on ReportTime, then re-arrange CurrentRow based on its position in DateField and this is the data you are expecting:
[
{
Id: 'xyz8',
CurrentRow: 0,
ReportTime: '2022-07-18T08:00:00+00:00',
ExitTime: null,
DateField: '2022-07-18'
},
{
Id: 'xyz7',
CurrentRow: 1,
ReportTime: '2022-07-18T09:00:00+00:00',
ExitTime: null,
DateField: '2022-07-18'
},
{
Id: 'wxyz0',
CurrentRow: 0,
ReportTime: '2022-07-19T00:00:00+00:00',
ExitTime: null,
DateField: '2022-07-19'
},
{
Id: 'wxyz1',
CurrentRow: 1,
ReportTime: '2022-07-19T00:00:00+00:00',
ExitTime: null,
DateField: '2022-07-19'
}
]
this is the code I came up with:
var tempRow = 0;
var tempDate = ''
YOUR_ARRAY
.sort((a, b) => (a.ReportTime > b.ReportTime) ? 1 : ((b.ReportTime > a.ReportTime) ? -1 : 0))
.forEach((row, i) => {
if (row.DateField != tempDate) {
tempDate = row.DateField
tempRow = 0
}
row.CurrentRow = tempRow
tempRow++
})

How to get min values among properties inside an array of objects?

In React I have an object like:
shirt : {
title : "Abc",
material : "cotton",
options : [
0 : {
price: 10,
color: red
},
1 : {
price: 20,
color: green
},
2 : {
price: 30,
color: blue
},
}
In the catalog page I want to display only the cheapest option ("From $10") for every shirt.
To display all shirts I use map function:
shirts.map((shirt) => (<div>{shirt.title}</div><div>{shirt.material}</div>))
How can I show only the cheapest price?
I can not use {shirt.options.price[0]} because the first element of the array is not always the cheapest price.
You could do:
const minPrice = Math.min(...shirt.options.map(({price}) => price))
const cheapeastShirt = shirt.options.find({price} => minPrice === price)

Problem updating object properties inside a promise-aware for loop in javascript

I am having a problem accessing updated object properties inside a for loop in Javascript.
let distribution = await ctx.db.query.distribution(
{
where: {
id,
},
},
`
{
id
clients {
id
wallet {
amount
}
}
}`,
);
let count = 0;
for (const client of distribution.clients) {
await ctx.db.mutation.updateWallet({
where: {
id: client.id,
},
data: {
amount: client.wallet.amount + someAmount,
},
});
distribution.clients[count].wallet.amount = client.wallet.amount + someAmount;
count++;
}
In the above code, I execute a graphQL query to fetch all information associated with a distribution. I then want to iterate through the associated clients array and update each client’s wallet. The same client may appear multiple times in this array and each time
their wallet must be updated.
A problem occurs when a wallet has already been updated in a previous iteration. When I try to update the amount a second time, the client.wallet.amount reflects the initial value of the wallet rather than value after the first update.
Clearly the property clients[count].wallet.amount attribute of the distribution object isn’t being updated after each iteration. I thought javascript objects were passed by reference, and therefore the object should be updated after each iteration.
Could someone explain to me why the distribution object property is not being updated and how I can update it correctly?
FYI: I cannot use other loops such as forEach as it is not promise-aware and does not suppose async/await
A problem occurs when a wallet has already been updated in a previous iteration.
Each wallet object is only modified once when the loop runs. Two or more wallet objects in the array may represent the same row in the database, but they are still distinct objects -- changing one will not change the other.
const wallets = [
{ id: 1, amount: 0 },
{ id: 2, amount: 0 },
{ id: 1, amount: 0 },
]
for (const wallet of wallets) {
wallet.amount = wallet.amount + 5
}
console.log(wallets[0]) // { id: 1, amount: 5 }
console.log(wallets[1]) // { id: 2, amount: 5 }
console.log(wallets[2]) // { id: 1, amount: 5 }
Note that we don't need to use a count variable at all. Because the const wallet is a reference to the original object in the array, if we modify it, we modify the original object.
If you want need to track the amounts by ID, you'd need to implement that logic. For example:
const wallets = [
{ id: 1, amount: 0 },
{ id: 2, amount: 0 },
{ id: 1, amount: 0 },
]
const amountsById = {}
for (const wallet of wallets) {
amountsById[wallet.id] = (amountsById[wallet.id] || wallet.amount) + 5
}
const updatedWallets = wallets.map(wallet => ({
...wallet,
amount: amountsById[wallet.id],
}))
console.log(updatedWallets[0]) // { id: 1, amount: 10 }
console.log(updatedWallets[1]) // { id: 2, amount: 5 }
console.log(updatedWallets[2]) // { id: 1, amount: 10 }

Trying to create a trending formula based on certain conditions

I have five articles with these initial properties:
const articles = [
{ id: 1, views: 92, likes: 0, shares: 2, trendingValue: ? },
{ id: 2, views: 14, likes: 2, shares: 1, trendingValue: ? },
{ id: 3, views: 39, likes: 3, shares: 1, trendingValue: ? },
{ id: 4, views: 87, likes: 0, shares: 1, trendingValue: ? },
{ id: 5, views: 8, likes: 1, shares: 0, trendingValue: ? }
];
I also have a global stats object that should be automatically updated once an article gets new views, likes or shares (or once a week):
const stats = {
totalArticles: 5,
totalViews: 240,
totalLikes: 6,
totalShares: 5,
trendingCriteria: 0
};
So far, I believe there is some sort of formula that can be done with articles' trendingValue and stats' trendingCriteria. Basically the articles that are "trending" need to have an equal or higher number than the criteria. Meaning that whenever an article gets a new view, share or like, trendingValue has to be updated in regards to it's percentage of views, likes and shares, by the global stats' counterparts.
An example (which doesn't exactly work) is:
A user views article 1.
This formula runs for the article to create its trendingValue:
const article = articles[0]; // Article with id 1
article.views++; // Increment the views count
stats.totalViews++ // Increment the total views count
let percentSum = (
(article.views / stats.totalViews) + // = 0.3833
(article.likes / stats.totalLikes) + // = 0
(article.shares / stats.totalShares) // = 0.4
); // = 0.7833
// The trendingValue needs to be a higher value of trendingCriteria
// before refreshing trendingCriteria.
article.trendingValue = (stats.trendingCriteria +
(percentSum / stats.trendingCriteria)
);
Next, trendingCriteria should be refreshed in regards to the updated article. The underlying logic is; if the new trendingCriteria is higher than the article's trendingValue, the article should no longer be "trending".
The third step is where I'm stuck. How do I create this value? Can this value be update for every single new view, like and share? Or do I have to update the value once a week or so?
Update
Thanks for all responses. Unfortunately I could not make any use of them since I'm yet confused what to do with the proposed solutions.
Anyhow, I tried another solution that makes use of an epoch timestamp and the average views, likes and shares. Not sure if it works in practice, so if anyone can confirm I'd be grateful.
function refreshArticleAtIndex(index, props) {
const data = articles[index];
// Increment props
if(props.view) { data.views++; stats.views++; }
else if(props.like) { data.likes++; stats.likes++; }
else if(props.share) { data.shares++; stats.shares++; }
// Refresh trendingRate
data.trendingRate = (() => {
const calcViews = data.views / stats.views;
const calcLikes = data.likes / stats.likes;
const calcShares = data.shares / stats.shares;
let value = Date.now() * (
(isFinite(calcViews) ? calcViews : 0) +
(isFinite(calcLikes) ? calcLikes : 0) +
(isFinite(calcShares) ? calcShares : 0)
);
return Math.round(value);
})();
}
function logArticles() {
const arr = articles.map(article => article);
arr.sort((a, b) => a.trendingRate > b.trendingRate ? -1 : 1);
arr.forEach(a => console.log(a.id +" |", a.trendingRate));
console.log("----------");
}
const stats = { views: 239, likes: 6, shares: 5 };
const articles = [
{ id: 1, views: 91, likes: 0, shares: 2, trendingRate: 0 },
{ id: 2, views: 14, likes: 2, shares: 1, trendingRate: 0 },
{ id: 3, views: 39, likes: 3, shares: 1, trendingRate: 0 },
{ id: 4, views: 87, likes: 0, shares: 1, trendingRate: 0 },
{ id: 5, views: 8, likes: 1, shares: 0, trendingRate: 0 }
];
console.log("ID | trendingRate");
// ================================================
// Add 1 view to article 1
refreshArticleAtIndex(0, { view: true });
// Add nothing to below articles, but refresh their trendingRate
refreshArticleAtIndex(1, {});
refreshArticleAtIndex(2, {});
refreshArticleAtIndex(3, {});
refreshArticleAtIndex(4, {});
logArticles();
// Add 1 like to article 1
refreshArticleAtIndex(0, { like: true });
logArticles();
The first log will show the correct order based on a combination of views, likes and shares for each article. Next, article 1 gets a like, which bumps it to the most trending article.
Question is if this is a working solution?
Trending probably should mean something like "top n% of activity" or "top n articles by activity".
Towards this end, you could simply save the trendingValue to an array like: { article: articleId, trendingValue: trendingValue}
Then when you go to find the most trending articles you would:
let cnt = trendingValues.length * myLimit
let i = 0
let trending = trendingValues.sort((a,b) => a.trendingValue > b.trendingValue).filter(() => i++ < cnt)
To use your language, trendingCriteria could be set to some minimum based on the set of articles. From there it could be fine tuned to ensure a certain minimum activity (as the average article age starts to grow).

Gridster serialize data to 1-5 order (recursive loop)?

I'm using the Gridster plugin, and I need to capture the newly dragged order in an 1-5 manner. I know that we choose row first, then order (column). So, row:1, order:1 would be id: grid_74. The next closest order number greater than 1 in row 1 is 5, so id: grid_78. How can I accomplish this?
1 - grid_74
2 - grid_78
(etc...)
var gridinfo = gridster.serialize()
I think you might just need a sort.
// Just setting up object array to match example:
var gridinfo = [
{ id: "grid_75", order: 5, row: 4 },
{ id: "grid_74", order: 1, row: 1 },
{ id: "grid_91", order: 9, row: 1 },
{ id: "grid_85", order: 5, row: 7 },
{ id: "grid_78", order: 5, row: 1 }
]
// This sort is what does all the magic.. it first sorts by row, then order.
// I lifted this bit of javascript ninjutsu from:
// http://www.sitepoint.com/sophisticated-sorting-in-javascript/
gridinfo.sort(function(a, b)
{
if(a.row === b.row)
{
return a.order < b.order ? -1 : a.order > b.order ? 1 : 0;
}
return a.row - b.row;
});
// Display sorted array:
for(var k=0; k<gridinfo.length; k++)
{
document.write('id: '+gridinfo[k].id+'<br>');
document.write('row: '+gridinfo[k].row+'<br>');
document.write('order: '+gridinfo[k].order+'<br>');
document.write('-------<br>');
}

Categories