Related
I'm new to javascript and react and working on my first mini project but I cannot figure out how to solve this.
In each "Order" model I have this array field called "orderItems" which holds an array of product models and within each product model there's a field called "shop". I want to get the "shop" value for all the products in orderItems and add it into a new array in "Order" model
Here is my schema:
{
orderItems: [
{
name: 'abc',
quantity: 1,
shop: 'abc',
image: '/images/cake.jpg',
price: 50,
_id: new ObjectId("62dbb03e90c4ca14ee3e06fd")
},
{
name: 'def',
quantity: 1,
shop: 'def',
image: '/images/cake.jpg',
price: 50,
_id: new ObjectId("62dbb03e90c4ca14ee3e06fd")
}
],
sellers: [],
shippingAddress: {
fullName: '123',
address: '123',
city: '123',
postalCode: '123',
country: '123'
},
paymentMethod: 'Paypal',
itemsPrice: 50,
shippingPrice: 10,
totalPrice: 60,
buyer: new ObjectId("62d6e48d8cd5cd2e62f6aeae"),
_id: new ObjectId("62dbcf88cf1bc8fc7b85cc0b"),
__v: 0
}
So I want to get 'abc', and 'def' from orderItems array and fill it in the sellers array. I can get the values but how do I fill it into the sellers array in the same model?
this is my api code
orderRouter.post(
'/', isAuth, expressAsyncHandler(async(req, res) => {
const newOrder = new Order({
orderItems: req.body.orderItems.map((x) => ({ ...x, product: x._id })),
shippingAddress: req.body.shippingAddress,
paymentMethod: req.body.paymentMethod,
itemsPrice: req.body.itemsPrice,
shippingPrice: req.body.shippingPrice,
totalPrice: req.body.totalPrice,
buyer: req.user._id,
sellers: [],
});
const order = await newOrder.save();
})
);
I tried using a loop and then order.sellers.push(order.orderItems[i].shop) and then saving again but its not updating in my database & in local storage the _id field was pushed into the array instead of shop
Step by step:
Declare a separated const orderItems above const newOrder.
Extract const sellers using a Set. You can also do it with an array or even an object, but Set will filter out duplicates automatically.
The create the order, using the 2 consts above, and remember to turn the Set into an array.
Should look something like this:
const orderItems = req.body.orderItems.map((x) => ({ ...x, product: x._id }));
const sellers = [...new Set(orderItems.map(x => x.shop))];
const newOrder = new Order({
orderItems,
sellers: [...sellers],
shippingAddress: req.body.shippingAddress,
paymentMethod: req.body.paymentMethod,
itemsPrice: req.body.itemsPrice,
shippingPrice: req.body.shippingPrice,
totalPrice: req.body.totalPrice,
buyer: req.user._id,
});
And here's a working example:
const orderItems = [{
name: 'P1',
quantity: 1,
shop: 'S1',
image: '/images/p1.jpg',
price: 50,
_id: '62dbb03e90c4ca14ee3e06fa',
}, {
name: 'P2',
quantity: 1,
shop: 'S2',
image: '/images/p2.jpg',
price: 50,
_id: '62dbb03e90c4ca14ee3e06fb',
}, {
name: 'P3',
quantity: 1,
shop: 'S1',
image: '/images/p3.jpg',
price: 50,
_id: '62dbb03e90c4ca14ee3e06fc',
}];
const sellersSet = new Set(orderItems.map(x => x.shop));
const sellersArray = [...sellersSet];
// See here why the conversion to array is needed:
console.log({ sellersSet, sellersArray });
Doc -
const array = [
{
user: new ObjectId("627913922ae9a8cb7a368326"),
name: 'Name1',
balance: 0,
_id: new ObjectId("627913a92ae9a8cb7a36832e")
},
{
user: new ObjectId("6278b20657cadb3b9a62a50e"),
name: 'Name2',
balance: 0,
_id: new ObjectId("6279133b2ae9a8cb7a368314")
},
{
user: new ObjectId("627913692ae9a8cb7a368319"),
name: 'Name3',
balance: 0,
_id: new ObjectId("627913872ae9a8cb7a368321")
},
{
user: new ObjectId("6278b24e57cadb3b9a62a513"),
name: 'Name4',
balance: 0,
_id: new ObjectId("6278b41ab18ff3dff84781bd")
}
]
Here, I want to remove the "_id" from all the objects in the array
I tried to use delete property but it didn't work
array.forEach(object=>delete object._id)
And When I tried the same array.forEach(object=>delete object._id) by removing new ObjectId in _id property of object in array it worked fine!
But as I am fetching this array from MongoDb,I can't remove this new ObjectId manually, So I need to fix this!!
Here, I got my answer
In the array
const array = [
{
user: new ObjectId("627913922ae9a8cb7a368326"),
name: 'Name1',
balance: 0,
_id: new ObjectId("627913a92ae9a8cb7a36832e")
},
{
user: new ObjectId("6278b20657cadb3b9a62a50e"),
name: 'Name2',
balance: 0,
_id: new ObjectId("6279133b2ae9a8cb7a368314")
},
{
user: new ObjectId("627913692ae9a8cb7a368319"),
name: 'Name3',
balance: 0,
_id: new ObjectId("627913872ae9a8cb7a368321")
},
{
user: new ObjectId("6278b24e57cadb3b9a62a513"),
name: 'Name4',
balance: 0,
_id: new ObjectId("6278b41ab18ff3dff84781bd")
}
]
I tried to use .map() and it did my work
let list = []
array.map((object)=>{
list.push({user: object.user,name: object.name,balance: object.balance})
})
console.log(list);
I need some idea!
Is there any possible way To separate user orders based on vendor email? I am trying to develop a multi-vendor project where vendors can be able to upload products. I am trying to do when a user orders from a different shop the orders need to be split based on vendor email.
Suppose a customer trying to buy from x vendor and y vendor products. When customers order the products the data look like the below array objects. It is difficult to show vendor orders in their dashboard who ordered your product. So I am trying to split the order based on email also the amount will be divided between the vendors from paymentDetail.amount when splitting the order.
[
{
_id: "622d70a49bd88b1599026318",
products: [
{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
vendor: {email: "vendor1#gmail.com"}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
],
paymentDetails: {
createdId: 1647145079,
date: "Sun Mar 13 2022",
amount: 700,
email: "user#gmail.com",
last4: "4242",
transaction: "p"
},
status: "Pending",
billing: {
country: "BD",
name: "Md. Fathe Karim",
phone: "+88010000000",
line1: "Madhabdi",
city: "Narshingdi",
postal_code: "1604",
state: "Bandarban"
}
}]
This is my POST request from frontend:
await fetch('https://guarded-ocean-73313.herokuapp.com/dashboard/orders', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
products: [...cart], paymentDetails: {
createdId: paymentIntent.created,
date,
amount: paymentIntent.amount,
email: emailRef.current?.value,
billing: paymentIntent.billing_details,
last4: paymentMethod.card.last4,
transaction: paymentIntent?.client_secret.slice('_secret')[0]
},
status: 'Pending',
billing: {
country: countryRef.current?.value,
name: nameRef.current?.value,
phone: phoneRef.current?.value,
line1: addressRef.current?.value,
city: cityRef.current?.value,
postal_code: zipRef.current?.value,
state: stateRef.current?.value,
}
})
})
.then(res => res.json())
This is my order API
app.post('/dashboard/orders', async (req, res) => {
const productDetail = req.body
const result = await unityMartOrdersCollection.insertOne(productDetail)
res.json(result)
})
My expectation is something like this:
[
{
_id: "622d70a49bd88b1599026318", // Vendor 1 Order
products: [
{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
vendor: {email: "vendor1#gmail.com"}
}
],
paymentDetails: {
createdId: 1647145079,
date: "Sun Mar 13 2022",
amount: 600, // price redcuded because we divided the product
email: "user#gmail.com",
last4: "4242",
transaction: "p"
},
status: "Pending",
billing: {
country: "BD",
name: "Md. Fathe Karim",
phone: "+88010000000",
line1: "Madhabdi",
city: "Narshingdi",
postal_code: "1604",
state: "Bandarban"
}
},
{
_id: "622d70a49bd88b1599026319", // Vendor 2 Order
products: [
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
],
paymentDetails: {
createdId: 1647145079,
date: "Sun Mar 13 2022",
amount: 200, // price redcuded because we divided the product
email: "user#gmail.com",
last4: "4242",
transaction: "p"
},
status: "Pending",
billing: {
country: "BD",
name: "Md. Fathe Karim",
phone: "+88010000000",
line1: "Madhabdi",
city: "Narshingdi",
postal_code: "1604",
state: "Bandarban"
}
}
]
I think it's possible by the reduce method?
can someone give me any idea how can I be able to display the vendor's order into their dashboard? If my thinking is wrong you can share your idea.
This may be one possible solution to achieve the desired objective:
Code Snippet
const groupByVendor = arr => (
arr.map(order => (
Object.values( // sub-objective 1 - get values from object
order.products.reduce(
(fin, p) => ({
...fin,
...(
[p.vendor.email] in fin
? {
[p.vendor.email]: {
...fin[p.vendor.email],
products: fin[p.vendor.email].products.concat([{...p}]),
paymentDetails: {
...structuredClone(fin[p.vendor.email].paymentDetails),
amount: fin[p.vendor.email].paymentDetails.amount + p.price
} // sub-objective 2 - add price to existing amount
}
}
: {
[p.vendor.email]: {
...structuredClone(order), // sub-objective 3 - add order info here
paymentDetails: {
...structuredClone(order.paymentDetails),
amount: p.price // sub-objective 2 - set amount to price
},
products: [{...p}]
}
}
)
}),
{}
)
)
)).flat()
);
const rawData = [{
_id: "622d70a49bd88b1599026318",
products: [{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
vendor: {
email: "vendor1#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
],
paymentDetails: {
createdId: 1647145079,
date: "Sun Mar 13 2022",
amount: 700,
email: "user#gmail.com",
last4: "4242",
transaction: "p"
},
status: "Pending",
billing: {
country: "BD",
name: "Md. Fathe Karim",
phone: "+88010000000",
line1: "Madhabdi",
city: "Narshingdi",
postal_code: "1604",
state: "Bandarban"
}
}];
console.log(groupByVendor(rawData));
Explanation
The idea is to break down the desired objective into simpler, more-manageable sub-objectives.
Sub-objective 1: A dictionary mapping vendors with orders
First, generate an object with props as the vendor email.
The values will be the actual order corresponding to the vendor
Once this object is created, all we need is the values array
Sub-objective 2: A mechanism to update the paymentDetailss amount
If processing a vendor that is not already present, set amount to price
If vendor already present, add price to existing amount
Sub-objective 3: Transform the structure of the object
The target requires each object in the array have paymentDetails, billing etc.
So, when generating the values for the vendor-object/dictionary/map, account for the corresponding transformations
The sub-objectives are marked in the code-snippet for reference.
Please use comments to ask any questions, clarifications, or suggest improvements.
NOTE
This answer employs structuredClone in order to perform deep-cloning of the order object.
My reference was Jeremy's this answer as well as this one
Modified Above Answer to Just Split Products without using structured clone , hope this might help
const groupByVendor = arr => (
arr.map(order => (
Object.values( // sub-objective 1 - get values from object
order.products.reduce(
(previousProduct, product) => ({
...previousProduct,
...(
[product.owner] in previousProduct
? {
[product.owner]: {
...previousProduct[product.owner],
products: previousProduct[product.owner].products.concat([{...product}]),
// sub-objective 2 - add price to existing amount
}
}
: {
[product.owner]: {
// sub-objective 3 - add order info here
products: [{...product}]
}
}
)
}),
{}
)
)
)).flat()
);
const rawData = [{
_id: "622d70a49bd88b1599026318",
products: [{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
owner: "vendor1#gmail.com"
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
owner: "vendor2#gmail.com"
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
owner: "vendor2#gmail.com"
},
]
}];
console.log(JSON.stringify(groupByVendor(rawData)));
I have a nested array of objects. I'm trying to group product objects that have the same value.
Each objects has a vendor property containing an email. I am trying to group the objects by matching vendor email
This is how my database looks like:
[
{
_id: "622d70a49bd88b1599026318",
products: [
{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
vendor: {email: "vendor1#gmail.com"}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
}
]
}]
I am trying to do it with the reduce method but the problem is with using map inside the reduce. It repeats the object many times. I am also unable to get the grouped objects.
const groupedMap = db.reduce(
(entryMap, e) => e.products.map((product) => entryMap.set(product.vendor.email, [...entryMap.get(product)||[], product])),
new Map()
);
The above code output is:
My expectation is:
[0: {"vendor1#gmail.com" => Array(1)}
key: "vendor1#gmail.com"
value: [{_id: '6223186e2278d4e502f5264a', title: 'Product number 1', price: 600, cartQuantity: 1, vendor: {email: "vendor1#gmail.com"}}],
1: {"vendor2#gmail.com" => Array(2)}
key: "vendor2#gmail.com"
value: [{_id: '6223186e2278d4e502f5264a', title: 'Product number 1', price: 600, cartQuantity: 1, vendor: {email: "vendor2#gmail.com"}},
{_id: '6223186e2278d4e502f5264a', title: 'Product number 1', price: 600, cartQuantity: 1, vendor: {email:"vendor2#gmail.com"}}
]
]
Loop through each item in the array and see if the vendor email exists as a key already in a dictionary, if it exists push it to that array, otherwise set the value of the vendor email key equal to an array with the current item in it
See code below
const data = [{
_id: "622d70a49bd88b1599026318",
products: [{
_id: "6223186e2278d4e502f5264a",
title: "Product number 1",
price: 600,
cartQuantity: 1,
vendor: {
email: "vendor1#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
},
{
_id: "622d4e9f9bd88b1599026317",
title: "asdas",
price: 100,
cartQuantity: 5,
vendor: {
email: "vendor2#gmail.com"
}
}
]
}];
const mapped = {};
data[0].products.forEach(item => {
if (item.vendor.email in mapped) return mapped[item.vendor.email].push(item);
mapped[item.vendor.email] = [item];
});
const expectedFormat = Object.keys(mapped).map(key => {
const o = {};
o[key] = mapped[key];
return o;
});
console.log(expectedFormat)
try to make an object where key is the value you group by. the next step is foreach in which you check each object in the array, whether the value you are looking for is in the object made - if not, then you filter the array by searched value and add the result to your object
i have my structure like this :
test{
_id: 60eadb64b72caa2ae419e085,
testid: 'hh',
time: 45,
testPassword: 123,
startTime: 2021-07-11T11:52:04.245Z,
Students: [
{
_id: 60eadb98b72caa2ae419e088,
submission: '#*#org 0h #*##*#ret#*#',
familyName: 'dsc',
firstName: 'ccccc',
group: 2,
time: 0.8772833333333333
},
{
_id: 60eadbb5b72caa2ae419e08c,
submission: '#*#org 0h #*##*#ret#*#',
familyName: 'eqf',
firstName: 'aaaaa',
group: 56,
time: 1.357
}
],
__v: 0
}
i want to get just the object that has the _id: 60eadb98b72caa2ae419e088 from the array of students like this
{
_id: 60eadb98b72caa2ae419e088,
submission: '#*#org 0h #*##*#ret#*#',
familyName: 'dsc',
firstName: 'ccccc',
group: 2,
time: 0.8772833333333333
}
you can search inside array of objects in mongoose like this
db.collection.find({"Students._id": yourId})
you can go as deep as you want
db.collection.find({"Students.users.info.name": username})
and for a single match you can use findOne like this
db.collection.findOne({"Students._id": yourId})
the if you want only the object inside the Students array you can find it by javascript find function
const wantedObject = myObj.Students.find(e => e._id === "60eadb98b72caa2ae419e088")
You can use following aggregate to find you required result, I have tried at my local it is working fine
db.users.aggregate([
{
$match:{
"Students._id":ObjectId("60eadb98b72caa2ae419e088")
}
},{
$unwind:"$Students"
},
{
$project: {
submission:"$Students.submission",
_id:"$Students._id",
familyName:"$Students.familyName",
firstName:"$Students.firstName",
group:"$Students.group",
time:"$Students.time",
}
},
{
$match:{
_id:ObjectId("60eadb98b72caa2ae419e088")
}
}
]);