SQL-like Inner Join for Javascript - javascript

const products = [{
id: 5,
productName: "Logitech Mouse",
unitprice: 35
},
{
id: 6,
productName: "Logitech Keyboard",
unitprice: 40
}
];
const cart = [{
id: 101,
userId: 3,
productId: 5,
quantity: 2
}];
totals = cart.reduce((r, {
productId: id,
quantity
}) =>
(r[id] = (r[id] || 0) + quantity, r), {}),
result = products.map(({
id,
productName,
unitprice
}) => ({
productName,
unitprice,
quantity: totals[id]
}));
console.log(result)
Currently, it prints two rows instead of one row. Second row should not be printed because there is only one row in cart. How do I the so-called inner join which return only one record which is for cart id 101?

If you want retain the cart with the "join", you can map the found product (without its id) and include the quantity.
const products = [{
id: 5,
productName: "Logitech Mouse",
unitprice: 35
}, {
id: 6,
productName: "Logitech Keyboard",
unitprice: 40
}];
const cart = [{
id: 101,
userId: 3,
productId: 5,
quantity: 2
}];
let joined = cart.map(item => {
let { id, ...rest} = products.find(p => p.id === item.productId);
return { ...rest, 'quantity' : item.quantity };
});
console.log(joined);
.as-console-wrapper { top: 0; max-height: 100% !important; }
If you want the total price of all items in the cart you will need to:
Reduce the cart by the items within it
Locate the product by its id
Add to the total, the unit price of the product times the quantity in the cart
const products = [{
id: 5,
productName: "Logitech Mouse",
unitprice: 35
}, {
id: 6,
productName: "Logitech Keyboard",
unitprice: 40
}];
const cart = [{
id: 101,
userId: 3,
productId: 5,
quantity: 2
}];
let total = cart.reduce((subtotal, item) => {
let product = products.find(p => p.id === item.productId);
return subtotal + product.unitprice * item.quantity;
}, 0);
console.log(total);
Short version:
let t = cart.reduce((s, i) => s + products.find(p => p.id === i.productId).unitprice * i.quantity, 0);

I recommend to use map function like this
const products = [{
id: 5,
productName: "Logitech Mouse",
unitprice: 35
},
{
id: 6,
productName: "Logitech Keyboard",
unitprice: 40
}
];
const cart = [{
id: 101,
userId: 3,
productId: 5,
quantity: 2
}];
result = cart.map(item => {
const product = products.find(product => item.productId === product.id);
return { id: item.id, quantity: item.quantity, productName: product.productName, unitprice: product.unitprice }
});
console.log(result);

While Mr. Polywhirl's answer is a cleaner and better solution, here is a simple edit to your code that solves your problem. The reason why your code returns two is because of the map. Replace it with filter and the condition on the presence of id to solve the issue.
const products = [{
id: 5,
productName: "Logitech Mouse",
unitprice: 35
},
{
id: 6,
productName: "Logitech Keyboard",
unitprice: 40
}
];
const cart = [{
id: 101,
userId: 3,
productId: 5,
quantity: 2
}];
totals = cart.reduce((r, {
productId: id,
quantity
}) =>
(r[id] = (r[id] || 0) + quantity, r), {}),
result = products.filter(({
id,
productName,
unitprice
}) => {
if (totals[id]) return ({
productName,
unitprice,
quantity: totals[id]
})
});
console.log(result)

Related

Compare two arrays javascript

I'm working on puppeteer in nike website.
I'm getting the sizes and stock and showing it as an array,
{ sku: 72961, skuname: 'Talla: 6 - Color: Azul', quantity: 2 },
{ sku: 72962, skuname: 'Talla: 6.5 - Color: Azul', quantity: 4 },
{ sku: 72963, skuname: 'Talla: 7 - Color: Azul', quantity: 5 },
{ sku: 72964, skuname: 'Talla: 7.5 - Color: Azul', quantity: 7 },
{ sku: 72965, skuname: 'Talla: 8 - Color: Azul', quantity: 6 },
{ sku: 72966, skuname: 'Talla: 8.5 - Color: Azul', quantity: 5 },
{ sku: 72967, skuname: 'Talla: 9 - Color: Azul', quantity: 8 },
{ sku: 72968, skuname: 'Talla: 9.5 - Color: Azul', quantity: 8 },
{ sku: 72969, skuname: 'Talla: 10 - Color: Azul', quantity: 6 },
{ sku: 72970, skuname: 'Talla: 10.5 - Color: Azul', quantity: 4 },
{ sku: 72971, skuname: 'Talla: 11 - Color: Azul', quantity: 1 },
{ sku: 72972, skuname: 'Talla: 11.5 - Color: Azul', quantity: 2 }
]
That is refreshing each 10 seconds so I'd like to find a way that the last array is compared to the previous to know if a new Size or quantity is added
My code
const pagina = "https://nike.cl"
const producto = "/dm0121-400-nike-dunk-low-retro-qs/p"
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900});
while (true) {
await page.goto(pagina + producto, { waitUntil: 'networkidle2' },);
var SKU = await page.evaluate("skuJson_0")
let filter = SKU.skus.filter( d => d.availablequantity > 0)
var SKUfiltered = filter.map(function(d){
return{
sku: d.sku,
skuname: d.skuname,
quantity: d.availablequantity
}})
console.log(SKUfiltered)
await page.waitForTimeout(10000)
I think the best solution is store the SKU data to check if exists previously and if the value are equals.
If the value pass the two checks you could store it in your "SKU register".
As next step, you could make another checks to filter the value. In your case only check if the quantity is zero.
As a complement, if you get many SKU and store a huge maybe you reach the memory limit. So you could remove it if the array is too big. To make that you could create an Array to store the values in order and remove if you reach some limit like 1000 elements.
In the next example, I simulate get the data in each getSKU execution. You must adapt the code to your solution:
// == FAKE DATA ==
let res_i = 0;
const res_data = [
[
{ sku: 1, skuname: "1", quantity: 0 }, // empty
{ sku: 2, skuname: "2", quantity: 1 },
],
[
{ sku: 1, skuname: "1", quantity: 5 },
{ sku: 2, skuname: "2", quantity: 1 }, // same quantity
{ sku: 3, skuname: "3", quantity: 0 }, // empty
],
[
{ sku: 1, skuname: "1", quantity: 0 }, // empty
{ sku: 3, skuname: "3", quantity: 3 },
{ sku: 4, skuname: "4", quantity: 3 },
],
];
// == END FAKE DATA ==
// An array to save the lastest SKU and a Map to store important values
const SKURegLog = [];
const SKURegdata = new Map();
// A funtion to simulate the data
function getSKU() {
const SKU = res_data[res_i++]; // Simulate the incoming data
return SKU.filter((v) => {
// Get the current SKU in the register
const curSKU = SKURegdata.get(v.sku);
// If exists and the quantity is the same, discard
if (curSKU !== undefined && curSKU.quantity === v.quantity) {
return false;
}
// If the SKU not exists in register add to the array
if (curSKU === undefined) {
SKURegLog.push(v.sku);
}
// Include the SKU in the register. If the array reach
// the limit (1000) delete the olders
SKURegdata.set(v.sku, {quantity: v.quantity});
if (SKURegLog.length > 1000) {
const oldSKU = SKURegLog.shift();
SKURegdata.delete(oldSKU);
}
// Check the current quantity
if (v.quantity === 0) {
return false;
}
// Include the SKU
return true;
});
}
console.log(getSKU());
console.log(getSKU());
console.log(getSKU());
console.log("= Register data:");
console.log(SKURegLog);
console.log(SKURegdata);
Output:
1: [ { sku: 2, skuname: '2', quantity: 1 } ]
2: [ { sku: 1, skuname: '1', quantity: 5 } ]
3: [ { sku: 3, skuname: '3', quantity: 3 }, { sku: 4, skuname: '4', quantity: 3 }]
== Register data:
[ 1, 2, 3, 4 ]
Map(4) {
1 => { quantity: 0 },
2 => { quantity: 1 },
3 => { quantity: 3 },
4 => { quantity: 3 }
}

TS/JS, Unable to sum more than one properties, using map set and get

I have been trying to create a summary of an array of objects where it's grouped by the value of one property and 2 or more properties should get summed.
But for some reason the way I am trying is only giving me 2 values the property I am grouping by and first property I am summing.
I am unable to sum the next property.
The array I am starting with
combinedItems
[
{
itemSi: 1,
productId: 'one',
taxableValue: 100,
taxValue: 10,
product: { id: 'one', productName: 'product one', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
},
{
itemSi: 2,
productId: 'two',
taxableValue: 100,
taxValue: 10,
product: { id: 'two', productName: 'product two', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
}
]
I need to be able to group by the taxName and sum the taxableValue and taxValue.
const summaryValues = new Map<any []>();
for(const {tax, taxableValue, taxValue} of combinedItems)
summaryValues.set(
tax.taxName,
(summaryValues.get(tax.taxName) || 0) + taxableValue,
(summaryValues.get(tax.taxName) || 0) + taxValue,
);
const summaries = [...summaryValues]
console.log(summaries);
const taxSummary = summaries.map(x => ({
taxName: x[0],
taxableValue: x[1],
taxValue: x[2]
}));
console.log(taxSummary)
The result I am getting
[ [ 'tax one', 200 ] ]
[ { taxName: 'tax one', taxableValue: 200, taxValue: undefined } ]
This is how the combined items are gotten:
const items: any[] = [
{
itemSi: 1,
productId: "one",
taxableValue: 100,
taxValue: 10
},
{
itemSi: 2,
productId: "two",
taxableValue: 100,
taxValue: 10
}
];
const products: any[] = [
{
id: "one",
productName:"product one",
taxId: "one"
},
{
id: "two",
productName:"product two",
taxId: "one"
}
]
const taxes: any[] = [
{
id: "one",
taxName:"tax one"
},
{
id: "two",
taxName:"tax two"
}
]
let combinedItems: any [] = []
combinedItems = items.map(x => {
let pdtItem = products.find(z => z.id === x.productId);
let taxItem = taxes.find(z => z.id === pdtItem.taxId);
let item = {...x, product: {...pdtItem }, tax: {...taxItem}};
return item;
});
console.log(combinedItems)
Map is a key-value store. What you're trying to do appears to be calling set with three arguments, whereas it only takes two (key and value).
If you need to produce multiple aggregations, you could store the results in an object:
const summaries = new Map();
for (const { tax: { taxName }, taxableValue, taxValue } of combinedItems) {
const currentSummary = summaries.get(taxName) || { taxableValue: 0, taxValue: 0 }
summaries.set(
taxName,
{ taxableValue: currentSummary.taxableValue + taxableValue, taxValue: currentSummary.taxValue + taxValue }
);
}

How to loop through two arrays of objects and get a new array with some data modified?

How to loop through two arrays of objects and get a new array with some data modified?
Arrays:
const products = [
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [
{
name: 'Jeans',
},
{
name: 'Tees',
},
];
Need new categories array like this with new prop productCount:
const newCategories = [
{
name: 'Jeans',
productCount: 2,
},
{
name: 'Tees',
productCount: 0,
},
];
I tried this way but it doesn't work:
const newArr = categories.map((category) => {
let count = 0;
const index = products.findIndex((product) => category.name === product.category);
if (index > -1) {
return {
...category,
productCount: count++,
};
}
return {
...category,
productCount: 0,
};
});
Increasing the count number will not in that case because it will always start with zero. Instead, you can use the filter() method to find the number of products with a specific category and assign this number to productCount attribute.
const products = [{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [{
name: 'Jeans',
},
{
name: 'Tees',
},
];
const newArr = categories.map((category) => {
const numberOfItems = products.filter((product) => category.name === product.category);
return {
...category,
productCount: numberOfItems.length,
};
});
console.log(newArr)
You can create an object and the transform it to array, something like this:
const products = [
{
brand: "Levis",
category: "Jeans"
},
{
brand: "Levis",
category: "Jeans"
},
{
brand: "Levis",
category: "Tees"
}
];
const categoriesObj = {};
products.forEach(({ brand, category }) => {
categoriesObj[category] ??= {
name: category,
productCount: 0
};
++categoriesObj[category].productCount;
});
const newCategories = Object.values(categoriesObj);
console.log(newCategories);
You can use the Array#Map method and add a productCount property using the Array#filter method
const products = [{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [{
name: 'Jeans',
},
{
name: 'Tees',
},
];
const newCategories = [...categories].map(category => ({
...category,
productCount: products.filter(product => product.category === category.name).length
}))
console.log(newCategories)
You could do this with Array.reduce(), incrementing the productCount for each item. This should also be efficient, requiring only one iteration of the products array.
We'd run the reduce over both arrays, ensuring that we'll end up with a productCount of zero where no products for that category exist.
const products = [ { brand: 'Levis', category: 'Jeans', }, { brand: 'Levis', category: 'Jeans', }, { brand: 'Levis', category: 'Tees', }, ];
const categories = [ { name: 'Jeans', }, { name: 'Tees', }, { name: 'Foo', } ];
const result = Object.values([...categories, ...products].reduce((acc, { brand, category, name }) => {
const key = name || category;
acc[key] = acc[key] || { name: key, productCount: 0 };
if (category) acc[key].productCount++;
return acc;
}, {}));
console.log('Result:', result);
.as-console-wrapper { max-height: 100% !important; }

filter array of objects by methods of another array of objects [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am making a food delivery app and I have two different array of objects. One of them is cartItems and the other is foodItems. The arrays can be of different sizes. So what do I want to loop over each array and check
if the ids of both the array match.
Note I want to check if the quantity exists then increment it by the new quantity else simply add a new quantity
check if itemDetails exists in foodItems array and if it exists, check if the price of cartItems matches of that foodItem, then update the cartItems object, else remove them.
if itemDetails does not exist then update the quantity of the item.
Update
If there are two items with similar id and price, the quantities should be added
Here is my cartItems:
let cartItems = [
{ id: 1, price: 120, quantity: 7 },
{ id: 2, price: 70, quantity: 4 },
{ id: 1, price: 70, quantity: 3 },
{ id: 3, price: 60, quantity: 1 },
{id: 1, price: 120, quantity: 2}
];
Here is my foodItems
let foodItems = [
{
id: 1,
name: "chicken",
itemDetails: [
{
price: 120,
details: "2 pcs of chicken biryani"
},
{
price: 70,
details: "1 pcs of chicken biryani"
}
],
},
{
id: 2,
name: "Mutton",
itemDetails: [
{
price: 120,
details: "Two pieces of mutton biryani",
},
{
price: 70,
details: "one pcs of mutton biryani"
},
],
},
{ id: 3, name: "Ice Cream", price: 60 },
];
This is my desired output
let filteredArrayOuput = [
{
id: 1,
name: "Chicken Biryani",
itemDetails: [
{
price: 120,
details: "Two pieces of chicken Biryani",
},
],
quantity: 7,
},
{
id: 2,
name: "Mutton Biryani",
itemDetails: [
{
price: 70,
details: "Two pieces of mutton biryani",
},
],
quantity: 4,
},
{
id: 1,
price: "Chicken Biryani",
quantity: 3,
itemDetails: [
{
price: 70,
details: "Two pieces of Chicken Biryani",
},
],
},
{ id: 3, price: 60, quantity: 1 },
];
This is what I have done till now
const filterFunc = (arr, price) => {
let filtered = arr.filter((item) => {
return item.price == price;
});
return filtered;
};
const filterArray = (arr1, arr2) => {
const filtered = arr2.filter((el) => {
let arr = arr1.find(({ id, quantity, price }) => {
if (el.id === id) {
if (el.itemDetails !== undefined && el.itemDetails.length !== 0) {
let itemDetails = el.itemDetails;
return (
(el.quantity = quantity),
(el.itemDetails = filterFunc(itemDetails, price))
);
} else {
return (el.quantity = quantity);
}
}
});
return arr;
});
return filtered;
};
console.log(filterArray(cartItems, foodItems))
You can check the below code.
Find existingFoodItem from FoodItems array
Find priceObj by comparing price
return new object with price details if itemDetails exists (checking with ?), else without price if no itemDetails exists.
let cartItems = [
{ id: 1, price: 120, quantity: 7 },
{ id: 1, price: 120, quantity: 1 },
{ id: 2, price: 70, quantity: 4 },
{ id: 1, price: 70, quantity: 3 },
{ id: 3, price: 60, quantity: 1 },
];
let foodItems = [
{
id: 1,
name: "chicken",
itemDetails: [
{
price: 120,
details: "2 pcs of chicken biryani"
},
{
price: 70,
details: "1 pcs of chicken biryani"
}
],
},
{
id: 2,
name: "Mutton",
itemDetails: [
{
price: 120,
details: "Two pieces of mutton biryani",
},
{
price: 70,
details: "one pcs of mutton biryani"
},
],
},
{ id: 3, name: "Ice Cream", price: 60 },
];
let result = [];
cartItems.forEach(cart => {
let esitingItem = result.find(r => r.id === cart.id && r.itemDetails.find(i => i.price === cart.price));
if(esitingItem){
esitingItem.quantity += cart.quantity;
return;
}
let existingFoodItem = foodItems.find(food => food.id === cart.id);
if(existingFoodItem){
let priceObj = existingFoodItem.itemDetails?.find(item => item.price === cart.price);
if(priceObj){
result.push({id:cart.id,name:existingFoodItem.name,itemDetails:[{...priceObj}],quantity:cart.quantity});
}
else{
return result.push({id:cart.id,name:existingFoodItem.name,quantity:cart.quantity});
}
}
});
console.log(result);

Concatenate array in vue.js

I have following array with me where records are shown per user
let data = [
{ userid: 1, placename: abc, price: 10 },
{ userid: 1, placename: pqr, price: 20 },
{ userid: 1, placename: xyz , price: 30},
{ userid: 2, placename: abc , price: 40},
{ userid: 2, placename: lmn , price: 50}
So, I want to transpose this data group by userid, by concatenation of place name and sum of price.
It should be look like below
UseId PlaceName Price
1 abc,xyz,pqr 60
2 abc,lmn 90
And I am binding this data to bootstrap vue b-table component
As of now I have done like this
groupby: function(array, key) {
const result = {};
array.forEach(item => {
if (!result[item[key]]) {
result[item[key]] = [];
}
result[item[key]].push(item);
});
return result;
},
And calling this while view is getting initialized,
groupby(this.list,'userid');
though I am getting all records in row as per user, but I am not able to concatenate the values and doing total.
While binding to table it is giving error 'Expected Arrat,got object'
Is anything missing here !
Any help on this appreciated !
Try out to filter the items that have the same userid then join place names and sum their prices :
array.forEach(item => {
if (!result[item[key]]) {
result[item[key]] = [];
}
let matched=array.filter(el=>el.UseId===item.UseId);
result[item[key]].push(
{
UseId:item.UseId,
placeName:matched.map(e=>e.placename).join(),
Price:matched.reduce((a, b) => a + b.price, 0)
});//push end
});
You can group your array item based on userid and push placename into array and sum up price for same userid.
const data = [ { userid: 1, placename: 'abc', price: 10 }, { userid: 1, placename: 'pqr', price: 20 }, { userid: 1, placename: 'xyz' , price: 30}, { userid: 2, placename: 'abc' , price: 40}, { userid: 2, placename: 'lmn' , price: 50}],
result = Object.values(data.reduce((r,o) => {
r[o.userid] = r[o.userid] || {userid: o.userid, placename: [], price: 0};
r[o.userid].placename.push(o.placename);
r[o.userid].price += o.price;
return r;
},{}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Whenever you feel like making an empty object and using array.map to populate it, try using .reduce instead
const data = [
{ userid: 1, placename: "abc", price: 10 },
{ userid: 1, placename: "pqr", price: 20 },
{ userid: 1, placename: "xyz" , price: 30},
{ userid: 2, placename: "abc" , price: 40},
{ userid: 2, placename: "lmn" , price: 50}
];
const groupBy = (arr, key) => Object.values(
arr.reduce((acc, item) => {
const k = item[key];
if (!acc[k]) {
acc[k] = {...item};
} else {
acc[k].placename += "," + item.placename;
acc[k].price += item.price;
}
return acc;
}, {})
);
console.log(groupBy(data, "userid"));
I split the solution in 3 steps, X, Y and Z:
X = group the rows by userid;
Y = concat the placenames and sum the prices;
Z = make a simpler object.
let data = [
{ userid: 1, placename: 'abc', price: 10 },
{ userid: 1, placename: 'pqr', price: 20 },
{ userid: 1, placename: 'xyz', price: 30 },
{ userid: 2, placename: 'abc', price: 40 },
];
const X = data.reduce((a, { userid, placename, price }) => { a[userid] = [...(a[userid] || []), { placename, price }]; return a }, {})
const Y = Object.entries(X).map(([userid, items]) => { return [userid, items.reduce((a, c) => { a.placename = [...a.placename.split(',').filter(s => !!s), c.placename].join(','); a.price += c.price; return a; }, { placename: '', price: 0 })]; });
const Z = Y.map(([userid, { placename, price }]) => ({ userid, placename, price }))
console.log(Z)
You can use a single line solution too:
let data = [
{ userid: 1, placename: 'abc', price: 10 },
{ userid: 1, placename: 'pqr', price: 20 },
{ userid: 1, placename: 'xyz', price: 30 },
{ userid: 2, placename: 'abc', price: 40 },
]
const doIt = (data) => Object.entries(data.reduce((a, { userid, placename, price }) => { a[userid] = [...(a[userid] || []), { placename, price }]; return a }, {})).map(([userid, items]) => { return [userid, items.reduce((a, c) => { a.placename = [...a.placename.split(',').filter(s => !!s), c.placename].join(','); a.price += c.price; return a; }, { placename: '', price: 0 })]; }).map(([userid, { placename, price }]) => ({ userid, placename, price }))
console.log(doIt(data))
Have fun!

Categories

Resources