Create random data during Promise.all - javascript

I'd like to create a mock data based on a JSON array to test front-end.
Object structure in the JSON array:
Mock:
{
category: string,
items: string[]
}
Category:
{
name: string,
products: Product[]
}
Product:
{
name: string,
prices: Price[]
}
Price:
{
date: Date,
value: number
}
I'd like to create random Prices for each Product, therefore I created the following helper function:
// Creates Price array with random values within a given time window
// `times` is a `lodash` function
const getRandomPrices = (numberOfDays, minValue, maxValue) => times(numberOfDays, n => ({
date: new Date(new Date().setDate(new Date().getDate() - n)),
value: Math.floor(Math.random() * maxValue) + minValue
}))
And I’m seeding my MongoDB database with the following function:
// data is Mock[]
// Price, Product and Category are MongoDB schemas
const createCategories = data.map(async c => {
const createProducts = c.items.map(async p => {
const prices = getRandomPrices(15, 100, 1000)
const createPrices = prices.map(price => Price.create(price))
return Product.create({
name: p,
prices: await Promise.all(createPrices)
})
})
return Category.create({
name: c.category,
products: await Promise.all(createProducts)
})
})
await Promise.all(createCategories)
console.log('done')
My problem is that I have same Price data for any Product in any Category and my questions are:
how can I randomize prices?
where am I doing wrong?

Related

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

useState delete array element in the state containing object

my state orderDetail contain orderDetail json
I am getting the _id of the order which I want to delete in function eg _id: 60f1ab20891ced4818b5ea87,
now I want to remove this order from the orders array which is in orderdetail and update the state.
orderdetail = {
_id: 60f1ab20891ced4818b5ea86,
totalPrice: '400',
orders: [
{
_id: 60f1ab20891ced4818b5ea87,
quantity: '1',
price: 200,
name: 'Caramel Latte',
category: 'Steaming Cups'
},
{
_id: 60f1ab20891ced4818b5ea88,
quantity: '1',
price: 200,
name: 'Cinnamon Latte',
category: 'Steaming Cups'
}
],
confirm: 'done',
timestamp: 1626450720332,
name: 'xxx',
email: 'xxx',
}
what I did is clone state then uses for loop to find an index of the order then remove that index element in clone then update state to clone. any other less computation method?
What you need to so is set a new object with the orders array filtered as well as a new totalPrice.
For example
const [orderDetail, setOrderDetail] = useState( /* whatever */ )
const deleteOrder = (id) => {
setOrderDetail(prev => {
// filter out the order by ID
const orders = prev.orders.filter(({ _id }) => _id !== id)
return {
...prev,
orders, // overwrite orders
totalPrice: orders.reduce((total, { quantity, price }) =>
total + quantity * price, 0), // calculate new total
timestamp: Date.now() // perhaps you want to update this too
}
})
}
This uses the functional update version of the useState() hook to easily get access to the previous state value.

Manipulating Data Array in React and Graphql

I'm attempting to manipulate this data in react with graphql. As you can see, I have this data or input in the graphql playground, and this is how I wanted the input to look:
In my frontend, I have a cartItem with an objects inside and array, including the product name, id, and so on. I wanted the input to look like the example I provided above. Is there a way to make that happen?
Codes and Data
This is how my cart's Item Data looks.
CartItem Data:
[
{
id: "6109401fd86d352a70e3694e",
name: "asasasasa",
sku: "sasa",
shippingTime: "1628812800000",
quantity: 1,
},
{
id: "61051c14f25d8830a8e238c0",
name: "Pringles Sour Cream & Onion Potato Crisps 158g",
sku: "sad89f79dsafs",
shippingTime: "1627084800000",
quantity: 1,
},
];
As stated in the preceding example, all I wanted was the product's id and quantity.
Order.js
const [cartItems, setCartItems] = useContext(CartContext);
const [createOrder, { data, loading }] = useMutation(CREATE_ORDER_MUTATION);
const qty = cartItems.map(({ quantity }) => {
return quantity;
});
const cartItemId = cartItems.map(({ id }) => {
return id;
});
function onSubmit() {
createOrder({
variables: {
qty: qty,
products: cartItemId,
paymentMethod: paymentMethod,
address: address,
},
})
}
Whenever I need to console someone. If you log the cartItemId, you'll get something like this:
Same goes with my qty.
Please let me know if you have any other questions or require any additional code, and I will gladly offer it.
Apollo Mutation:
const CREATE_ORDER_MUTATION = gql`
mutation createOrder(
$qty: Int!
$products: String!
$paymentMethod: String!
$address: String!
) {
createOrder(
orderedItems: [{ qty: $qty, products: $products }]
paymentMethod: $paymentMethod
address: $address
) {
id
orderedItems {
qty
products {
id
name
sku
description
}
}
}
}
`;
The code below will transform the cartItems into the desired result. You can loop through the cartItems and create an object with the required structure for each item.
const orderedItems = cartItems.map(({ id, quantity }) => {
return {
qty: quantity,
products: id,
};
});
Complete code will look something like this
const [cartItems, setCartItems] = useContext(CartContext);
const [createOrder, { data, loading }] = useMutation(CREATE_ORDER_MUTATION);
// Restructure the array to desired format
const orderedItems = cartItems.map(({ id, quantity }) => {
return {
qty: quantity,
products: id,
};
});
console.log(orderedItems); // To check if it looks correct
function onSubmit() {
createOrder({
variables: {
orderedItems: orderedItem,
paymentMethod: paymentMethod,
address: address,
},
})
}

JavaScript Combine two arrays into one object

I have two arrays, slicesRank and slicesCount with following structure. Each element has id and value, which is an array of 46. values is composed of date and measurement.
e.g. sliceRank[0]:
{id: Catan=rank, values(Array(46)) : {date, measurement} }
e.g. sliceCount[0]:
{id: Catan=count, values(Array(46)) : {date, measurement} }
What should I do if I want to combine the elements with the same prefix in id names. For example, the first element in this two arrays.
The desired sturcture would be
{id: Catan, values(Array(46)) : {date, count, rank} }
I tried the following, but the values shows undifined.
for(i=0; i<slicesRank.length; i++) {
var newElement = {};
newElement['id'] = slicesRank[i].id.replace('=rank', '');
newElement['values'] = {
date: slicesRank[i].date,
rank: slicesRank[i].measurement,
count: slicesCount[i].measurement
};
sliceNew.push(newElement);
};
The structure of slicesRank is like this:
Here's a sample transformation that you can try:
const combined = slicesRank.map((rank) => {
const id = rank.id.replace("=rank", "");
const count = slicesCount.find(
(count) => count.id.replace("=count", "") === id
);
return {
id,
values: rank.values.map((val, index) => ({
date: val.date,
rank: val.measurement,
count: count?.values[index].measurement
}))
};
});
Here's a working example
https://codesandbox.io/s/awesome-lovelace-e31zj?file=/src/index.js
By slice I think you mean Array.
const combinedArray = sliceRank.map((sliceItem, itemIndex) => {
return {
id,
values: sliceItem.values.map(({ date, measurement }, valueIndex) => ({
date,
count: sliceCount[itemIndex][valueIndex].measurement,
rank: measurement,
}))
}
})
This solution returns an array of objects combined using sliceRank and sliceCount. So now each array item now contains values of structure { date, count, rank }. Array.map is immutable so both slices will be the same.
You can try this.
let sliceRank=[{id: "Catan=rank", values : [{"date":"10/10/2020", "measurement":120} ]}];
let sliceCount=[{id: "Catan=count", values :[{"date":"10/10/2020", "measurement":20} ] }];
let newData=[];
const data = sliceRank.map((slice, sliceIndex) => {
return {
id:slice.id.split("=")[0],
values: slice.values.map(({ date, measurement }, valueIndex) => ({
date,
rank: measurement,
count: sliceCount[sliceIndex].values.map(r=> r.measurement)[0],
}))
}
})
console.log(data);

Insert online shopping cart items into MongoDB using Mongoose

I am attempting to insert a cart of items as a JSON object into a MongoDB collection using a mongoose schema.
The customer's ID is getting stored (which comes from the User DB), but the cart items are not. Here is my code:
Sample order data contained in local variable app.js called cartData: { data:[] }:
{
data: [
item {
name: "Product Name 1",
price: '2.99',
sku: '13579',
count: 8
},
item {
name: 'Product Name 2',
price: '21.99',
sku: '24680',
count: 2
}
]
}
Cart.js (Cart Schema):
const mongoose = require("mongoose")
const CartSchema = new mongoose.Schema({
customerID: {
type: String,
required: true
},
cartContents: {
type: [Object]
},
date: {
type: Date,
default: Date.now
}
}, { collection: "ordersDB" })
const Cart = mongoose.model('Cart', CartSchema)
module.exports = Cart
app.js (Order Submit Code):
const Cart = require("../models/Cart")
const customerID = req.user.customerID //Acquired from user database
const newOrder = new Cart({
customerID,
cartData
})
newOrder.save()
.then(customer => {
req.flash("successful", "Your order has been submitted!")
res.redirect("/somepage")
})
.catch(err => console.log(err))
Result:
_id: abcd1234
> cart: Object
> type: Array
> <The Infinite Abyss Of Nothingness aka Empty>
customerID: "1234567890"
date: 2019-12-11T21:14:40.825+00:00
__v: 0
Any insight on this problem would be greatly appreciated.
Based on provided schema Mongoose expects you to pass a field called cartContents. Any other field not compatible with your schema will be ignored. To fix that just name your field explicitly:
const newOrder = new Cart({
customerID,
cartContents: cartData
})

Categories