How to get highest difference between two numbers in a JSON object - javascript

I'm working with NodeJS to create a "Featured Product" widget on a website. I have a JSON object with SKU, price, and sale_price. What's the best way to get the SKU of the item that has the highest discount (Difference between price and sale_price)?
I tried doing it by for looping through the items and find the difference between price and sale_price, push the results to an array then get the max, but I cannot get the SKU at that point.
Example of the JSON object that I have:
{ "item_number":12341231, "price":"250", "sale_price":"219.99"},
{ "item_number":12341232, "price":"210", "sale_price":"209.99"},
{ "item_number":12341233, "price":"20", "sale_price":"12.99"},
{ "item_number":12341234, "price":"150", "sale_price":"19.99"},
{ "item_number":12341235, "price":"60", "sale_price":"29.99"},
{ "item_number":12341236, "price":"10", "sale_price":"5.99"}
];
For example the program would return 1231234 as the SKU of the featured item, because the discount is ~$130.
I just want a quick solution, don't worry about performance.

You could reduce the array with a single loop and take the one with the greatest delta.
var array = [{ item_number: 12341231, price: "250", sale_price: "219.99" }, { item_number: 12341232, price: "210", sale_price: "209.99" }, { item_number: 12341233, price: "20", sale_price: "12.99" }, { item_number: 12341234, price: "150", sale_price: "19.99" }, { item_number: 12341235, price: "60", sale_price: "29.99" }, { item_number: 12341236, price: "10", sale_price: "5.99" }],
result = array.reduce((a, b) =>
a.price - a.sale_price > b.price - b.sale_price ? a : b);
console.log(result);

If performance is not an issue, you can sort your products in descending order and get the first one from the sorted result:
const data = [
{ "item_number":12341231, "price":"250", "sale_price":"219.99"},
{ "item_number":12341232, "price":"210", "sale_price":"209.99"},
{ "item_number":12341233, "price":"20", "sale_price":"12.99"},
{ "item_number":12341234, "price":"150", "sale_price":"19.99"},
{ "item_number":12341235, "price":"60", "sale_price":"29.99"},
{ "item_number":12341236, "price":"10", "sale_price":"5.99"}
];
const maxDiffProduct = data.sort((a, b) => (b.price - b.sale_price) - (a.price - a.sale_price))[0];
console.log(maxDiffProduct.item_number);

Related

Change the positive number to negative number in array of object

Given array of object in database:
detail : [
0: {
Code: "Code 1",
Price: "1.00",
IncTaxPrice: "1.20",
Tax:"0.20",
},
1: {
Code: "Code 2",
Price: "9.00",
IncTaxPrice: "9.20",
Tax:"0.20",
}
]
Output i want with key and value negative (for eg)
[
{
Code: "Code 1",
Price: "-1.00",
IncTaxPrice: "-1.20",
Tax: "-0.20",
},
{
Code: "Code 2",
Price: "-9.00",
IncTaxPrice: "-9.20",
Tax: "-0.20",
},
];
I tried with the map, filter function but it gave an error I guess I am missing something.
After it filters properly I will use -Math.abs(), to convert positive to negative.
let final = detail.map(a => Object.values(a).filter(v => typeof v === 'number'))
the element like price,tax are something like 8 different elements of numbers and amounts.
Thanks for #VLAZ suggestion in the comment. I think you can filter by the key using Object.keys().
Example below:
const detail = [
{
Code: "Code 1",
Price: "1.00",
IncTaxPrice: "1.20",
Tax: "0.20",
},
{
Code: "Code 2",
Price: "9.00",
IncTaxPrice: "9.20",
Tax: "-0.20",
},
];
let final = detail.map(x => ({
Code: x.Code,
Price: -Number(x.Price),
IncTaxPrice: -Number(x.IncTaxPrice),
Tax: -Number(x.Tax),
}));
console.log(final);
You should wrap your 0, 1 indexes in curly brackets as it is an array of objects. You can't just define it as you did because indexes 0 and 1 are not just numbers (fex. [0,1,2] is valid but not [0:{code:...},1:{code:...}] They are contining an object inside, so they are objects and you can't map if your array of objects is not properly defined as:
[{0:{code:..}},{1:{code:..}}.
Also using typeof filter wont' work because all values are type string.
I would go like this:
let detail = [ {
0: {
Code: "Code 1",
Price: "1.00",
IncTaxPrice: "1.20",
Tax:"0.20",
}},
{1: {
Code: "Code 2",
Price: "9.00",
IncTaxPrice: "9.20",
Tax:"0.20",
}}
]
detail.map(el=>{
el[Object.keys(el)[0]]['Price']=(-parseFloat(el[Object.keys(el)[0]]['Price'])).toString()
el[Object.keys(el)[0]]['IncTaxPrice']=(-parseFloat(el[Object.keys(el)[0]]['IncTaxPrice'])).toString()
el[Object.keys(el)[0]]['Tax']=(-parseFloat(el[Object.keys(el)[0]]['Tax'])).toString()
return
}
)

Apply Combo Discount to a Food Order

An app lets users order food from a menu. The menu has three types of selection: main, drink and dessert. A feature needs to be added which will discount the price by 10% for every main+drink combo (10% off every combo). All items ordered by the customer are stored in an array like so:
order = [
{id: 4, count: 1, type: "main", price: 10}
{id: 5, count: 2, type: "drink", price: 9.5}
]
As you can see, each item the customer orders has a count property. How can I apply the discount without mutating the order array or any of the object properties? Ideally I'd like to loop through the array, determine total number of combos (in the example above it would be 1), determine the total discount value and pass that value to another function which computes the order total. If anyone can suggest a better way of doing it, I'm all ears (or eyes in this case).
Also, what is the best way to express this problem from a technical point of view?
const userOrder = [
{ id: 4, count: 1, type: "main", price: 200 },
{ id: 5, count: 1, type: "drink", price: 100 }
];
const orderInfo = userOrder.reduce((acc, cur) => {
console.log('cur', cur)
if (acc[cur.type]) {
return {
...acc,
[cur.type]: cur.count,
totalAmount: (cur.count * acc.totalAmount)
}
} else {
return {
...acc,
[cur.type]: cur.count,
totalAmount: (cur.count * cur.price ) + acc.totalAmount
}
}
}, {
main: 0,
drink: 0,
totalAmount: 0
});
const noOfComobosPresent = Math.min(orderInfo.main, orderInfo.drink);
const totalDiscountValue = noOfComobosPresent * 10;
const finalAmount = orderInfo.totalAmount - ((orderInfo.totalAmount * totalDiscountValue ) / 100) ;
console.log('finalAmount', finalAmount)

Nested arrays with objects, lodash meanBy

Can someone please help me understand how to make this work. Everytime I feel like I start to understand arrays and objects in Javascript it turns out that I still don't.
I'm trying to get the average of all prices in the following datastructure by using lodash meanBy
[
{
date: "2019-12-17",
items: [
{ id: "1", state: "accepted", price: "90.5" },
{ id: "2", state: "rejected", price: "20.0" },
{ id: "3", state: "open", price: "10.5" },
]
},
{
date: "2019-12-18",
items: [
{ id: "4", state: "open", price: "450.0" },
{ id: "5", state: "rejected", price: "40.1" },
{ id: "6", state: "accepted", price: "50.9" },
]
}
]
If you provide the answer, can you also please try to explain how you select something nested in items, because that's as far as I get before I get lost.
In this case instead of selecting nested values, it's easier to flatten the items to a single array, and then apply _.meanBy(). In addition, the prices are strings, and not numbers, so you'll need to convert them.
Flatten the items to a single array with Array.flatMap(), and then use _.meanBy(), and get the numeric values of the prices:
const data = [{"date":"2019-12-17","items":[{"id":"1","state":"accepted","price":"90.5"},{"id":"2","state":"rejected","price":"20.0"},{"id":"3","state":"open","price":"10.5"}]},{"date":"2019-12-18","items":[{"id":"4","state":"open","price":"450.0"},{"id":"5","state":"rejected","price":"40.1"},{"id":"6","state":"accepted","price":"50.9"}]}]
const result = _.meanBy(_.flatMap(data, 'items'), o => +o.price)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Another approach is to get the general average, by getting the average of each items array separately , and then getting the average of all averages.
const data = [{"date":"2019-12-17","items":[{"id":"1","state":"accepted","price":"90.5"},{"id":"2","state":"rejected","price":"20.0"},{"id":"3","state":"open","price":"10.5"}]},{"date":"2019-12-18","items":[{"id":"4","state":"open","price":"450.0"},{"id":"5","state":"rejected","price":"40.1"},{"id":"6","state":"accepted","price":"50.9"}]}]
const result = _.meanBy(data, ({ items }) => _.meanBy(items, o => +o.price))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Delimited List from Nested JavaScript Array

I have a simple JavaScript object that contains nested arrays.
All I'm looking for here us to return a comma delimited list of the "productID' values that are present at "digitalData.transaction.item.productInfo[i].productID[j]"
I appreciate the help.
Here's an example of the JS (sorry for the length, but better dafe than sorry I guess):
window.digitalData = {
transaction: {
purchaseID: "30010819", //Typically the same as transactionID
transactionID: "30010819", //Unique Identifier for this transaction
item: [{ //Array of items in this transaction
productInfo: {
productID: "63493",
color: "Fuscia", //color if this product has colors
size: "M (8-10)", //size if this product has sizes
sku: "63493-12456", //sku
inventoryStatus: "In Stock", // Mirror the on-site messaging
skuAttr: [{ // extensible array of sku attributes and values
typeLabel: "Color",
valueCode: "FSA",
valueLabel: "Fuscia"
}, {
typeLabel: "Size",
valueLabel: "M (8-10)"
}]
},
price: {
currency: "USD"
},
quantity: 1
}, {
productInfo: {
productID: "55027",
color: "", //color if this product has colors
size: "", //size if this product has sizes
sku: "55027", //sku if known. otherwise use productID
inventoryStatus: "Low Stock", // Mirror the on-site messaging
skuAttr: [] //Empty array if no sku attributes exist
},
price: {
currency: "USD"
},
quantity: 2
}]
}]
}
You can do it that way:
digitalData.transaction.item.map(x => x.productInfo.productID).join(',')

Iterating through array produced by MongoDB aggregation query

Good afternoon all,
I am having a really tough time working with aggregation queries in MongoDB 3.4. I have a problem that is asking me to do push the results of my aggregation query into an empty array called categories which I have been able to do successfully using this code:
var categories = [];
database.collection("item").aggregate([{
$group : {
_id : "$category",
num : {$sum : 1}
}},
{$sort:{_id:1}}]).toArray(function(err, data){
categories.push(...data);
callback(categories);
console.log(categories);
})
}
categories looks like this:
[ { _id: 'Apparel', num: 6 },
{ _id: 'Books', num: 3 },
{ _id: 'Electronics', num: 3 },
{ _id: 'Kitchen', num: 3 },
{ _id: 'Office', num: 2 },
{ _id: 'Stickers', num: 2 },
{ _id: 'Swag', num: 2 },
{ _id: 'Umbrellas', num: 2 } ]
Next I have the following task:
In addition to the categories created by your aggregation query,
include a document for category "All" in the array of categories
passed to the callback. The "All" category should contain the total
number of items across all categories as its value for "num". The
most efficient way to calculate this value is to iterate through
the array of categories produced by your aggregation query, summing
counts of items in each category.
The problem is that it seems like inside my .toArray() method the data parameter sometimes acts like an array and sometimes not. For example if I wanted to add perhaps just the value of the num key to the categories array like so: categories.push(...data["num"]) I get an error stating undefined is not iterable.
Since I cannot iterate over each data.num key I cannot extract it's value and add it to a running total of all data.num values.
What am I not understanding about what is going on here?
You don't need to use application logic to group data, mongoDB aggregation is made for this task. Add another $group to your query with a new field All that $sum your $num field and $push all documents to a new field called categories :
db.item.aggregate([{
$group: {
_id: "$category",
num: { $sum: 1 }
}
}, { $sort: { _id: 1 } }, {
$group: {
_id: 1,
All: { $sum: "$num" },
categories: {
$push: {
_id: "$_id",
num: "$num"
}
}
}
}])
It gives :
{
"_id": 1,
"All": 23,
"categories": [{
"_id": "Swag",
"num": 2
}, {
"_id": "Office",
"num": 2
}, {
"_id": "Stickers",
"num": 2
}, {
"_id": "Apparel",
"num": 6
}, {
"_id": "Umbrellas",
"num": 2
}, {
"_id": "Kitchen",
"num": 3
}, {
"_id": "Books",
"num": 3
}, {
"_id": "Electronics",
"num": 3
}]
}
For consuming the output, data is an array, to access the first element use data[0] :
var categories = [];
database.collection("item").aggregate([{
$group: {
_id: "$category",
num: { $sum: 1 }
}
}, { $sort: { _id: 1 } }, {
$group: {
_id: 1,
All: { $sum: "$num" },
categories: {
$push: {
_id: "$_id",
num: "$num"
}
}
}
}]).toArray(function(err, data) {
var totalCount = data[0]["All"];
console.log("total count is " + totalCount);
categories = data[0]["categories"];
for (var i = 0; i < categories.length; i++) {
console.log("category : " + categories[i]._id + " | count : " + categories[i].num);
}
})
What I wanted to achieve was pushing or unshifting as we'll see in a moment an object that looked like this into my categories array:
var allCategory = {
_id: "All",
num: [sum of all data.num values]
}
I ended up messing with .reduce() method and used it on the categories array. I got lucky through some console.log-ing and ended up making this:
var categories = [];
database.collection("item").aggregate([{
$group : {
_id : "$category",
num : {$sum : 1}
}},
{$sort:{_id:1}}]).toArray(function(err, data){
categories.push(...data);
var sum = categories.reduce(function(acc, val){
// console.log(acc, val["num"])
return acc + val["num"]
},0);
var allCategory = {
_id: "All",
num: sum
}
categories.unshift(allCategory)
callback(categories);
})
First I use a spread operator to push all the objects from data into categories. Then declare sum which runs .reduce() on categories returning the accumulation of val["num"] which is really data.num (console log is life). I create the allCategory document/object then use .unshift to place it at the beginning of my categories array (this placement was a requirement) then use my callback.
I think it's a hacky way of accomplishing my goal and I had to go through some trial and error as to the correct order of methods and variables in my .toArray(). Yet it worked and I learned something. Thanks for the help #Bertrand Martel .

Categories

Resources