Related
I'm trying to create an object according to my model in mongoose using a controller, but I'm running into a problem that the last array nesting with prize patterns is not being written. Theoretically it is, but it is empty. I do not understand what the problem is, since I cannot add the necessary value to it even after creating the object through the constructor and after that doing something like: newGame.prizes = prizes;
With this behavior, all other properties within the prize property appear in the object, but the pattern array is empty.
Here is what my model looks like:
const GameSchema = mongoose.Schema({
type: String,
roundId: String,
userId: String,
calloutNumbersCount: Number,
tickets: [
{
id: String,
columns: [[Number]],
},
],
prizes: [
{
id: String,
name: String,
nameLocaleKey: String,
winAmount: Number,
patterns: [
{
type: String,
count: Number,
},
],
},
],
ticketPrice: Number,
boughtTicketIds: [String],
ended: Boolean,
});
Controller:
function createGame(gameType, userId) {
const currentGameConfig = config[gameType];
console.log("Controller");
currentGameConfig.prizes.map((el) => console.log(el.patterns));
const roundId = nanoid(LENGTH_OF_ROUND_ID);
const game = new Game({
type: currentGameConfig.type,
roundId,
userId,
calloutNumbersCount: currentGameConfig.callout.numbersCount,
tickets: [
{
id: 123, // temp
columns: [[0]], // temp
},
],
prizes: currentGameConfig.prizes,
ticketPrice: currentGameConfig.tickets.price,
boughtTicketIds: ["1", "2"], // temp
ended: false,
});
return game;
}
Place of creation and modification of the object in the route:
if (!game) {
const newGame = gameController.createGame(type, userId);
// newGame.prizes = currentGameConfig.prizes;
Game.addGame(newGame, (err, game) => {
if (err) {
res.json({ success: false, message: err.message });
throw err;
}
return res.json({
roundId: newGame.roundId,
});
});
}
Expected result:
The result:
EDITED
CurrentGameConfig:
{
type: 'BINGO_75',
name: 'Bingo 75',
nameLocaleKey: 'GAMES.BINGO_75',
prizes: [
{
name: 'Prize 1',
nameLocaleKey: 'PRIZES.BINGO_75.PRIZE_1',
winAmount: 10,
patterns: [Array]
},
{
name: 'Prize 2',
nameLocaleKey: 'PRIZES.BINGO_75.PRIZE_2',
winAmount: 10,
patterns: [Array]
},
{
name: 'Prize 3',
nameLocaleKey: 'PRIZES.BINGO_75.PRIZE_3',
winAmount: 10,
patterns: [Array]
},
{
name: 'Prize 4',
nameLocaleKey: 'PRIZES.BINGO_75.PRIZE_4',
winAmount: 10,
patterns: [Array]
},
{
name: 'Full house',
nameLocaleKey: 'PRIZES.BINGO_75.PRIZE_5',
winAmount: 10,
patterns: [Array]
}
],
tickets: { price: 10, quantity: 72, grid: { cols: [Object], rows: [Object] } },
callout: { numbersCount: 25 }
}
In node.js patterns look like [Array], but if display each pattern it look like:
[
{type: 'HORIZONTAL', count: 1},
{type: 'VERTICAL', count: 1},
{type: 'DIAGONAL', count: 1}
]
Question:
Sorry if I cant summarize the problem in a nut shell, so I try to explain it in details.
I try to construct a object by using a input. However my consolidated results containing only one item, while expecting to have more than one.
Q2:In addition to the bug, may I seek for a answer that could avoid issue with array manipulation when I try to copy value from one array to a new variable, then change the value in it?
Problem:
Input:
[ { name: 'Balanced',
allocations: [ [Object], [Object], [Object] ] },
{ name: 'Balanced Plus',
currency: 'GBP',
allocations: [ [Object], [Object], [Object] ] },
{ name: 'Conservative',
currency: 'GBP',
allocations: [ [Object], [Object], [Object] ] },
{ name: 'Growth',
currency: 'GBP',
allocations: [ [Object], [Object], [Object] ] },
{ name: 'Income',
currency: 'GBP',
allocations: [ [Object], [Object], [Object] ] } ]
Expected output:
{ US: { allocation: { Balanced: [Array] , Balanced Plus: [Array], Conservative: [Array], Growth: [Array], Income: [Array]} } }
Result:
{ US: { allocation: { Income: [Array] } } }
Below is my present code:
const a = [
{
name: "Balanced",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Balanced Plus",
currency: "GBP",
allocations: [
{
id: "2238",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Conservative",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2300",
},
],
},
{
name: "Growth",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Income",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2300",
},
],
},
];
console.log(a);
const trans = (a) => {
const result = a.reduce((pre, cur) => {
const allocation = { [cur.name]: cur.allocations };
return { ...pre, allocation };
}, {});
return result
};
const b = { US: trans(a) };
console.log(b);
Here I've turned "US.allocation" into an object with property names like "Balanced", "Conservative" etc, with the appropriate allocations array as the property value.
const a = [
{
name: "Balanced",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Balanced Plus",
currency: "GBP",
allocations: [
{
id: "2238",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Conservative",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2300",
},
],
},
{
name: "Growth",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2269",
},
],
},
{
name: "Income",
currency: "GBP",
allocations: [
{
id: "2241",
},
{
id: "1175",
},
{
id: "2300",
},
],
},
];
const b = {
US: {
allocation: Object.fromEntries(a.map(el => [el.name, el.allocations]))
}
};
console.log(b);
My issue today is with MongoDB and mongoose in javascript. So first off I have this schema:
var playerModel = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "Users",
},
class: {
type: String,
required: true,
},
level: {
type: Number,
default: 1,
},
spells: {
type: [String],
default: ["", "", "", "", ""],
},
inventory: [], <- IMPORTANT
toolbelt: {
axe: [{}],
pickaxe: [{}],
fishingrod: [{}],
hammer: [{}],
saw: [{}],
sewingkit: [{}],
knife: [{}],
gemkit: [{}],
food: [{}],
potion: [{}],
},
gear: {
weapon: [{}],
head: [{}],
chest: [{}],
gloves: [{}],
legs: [{}],
shoes: [{}],
earrings: [{}],
ring: [{}],
necklace: [{}],
},
gold: {
type: Number,
default: 0,
},
bagSize: {
type: Number,
default: 20,
},
skills: {
type: [userSkills],
default: defaultSkills,
},
});
and my problem is with inventory: [].
In my code I manually push items in my array which save properly in the database, but whenever I wanna modify a field of one of my array object, it won't update it like a qty for example:
player.inventory[i].qty += 1; //Where player is my model containing my inventory
...
player.save()
.then((doc) => console.log("DOC", doc))
.catch((err) => console.log("ERR", err));
and the doc returned look something like this:
...
inventory: [
{
_id: 626a1468cdbeced19102942d,
slug: 'crude_campfire',
qty: 1,
charges: 19,
efficiency: -0.2
},
{ _id: 626a14e7530afad2c5c1894c, slug: 'wheat', qty: 1 },
{ _id: 626a14f1530afad2c5c1894d, slug: 'carrot', qty: 1 },
{ _id: 626a150f530afad2c5c1894e, slug: 'potato', qty: 1 },
{ _id: 626a155b530afad2c5c1894f, slug: 'red_bream', qty: 1 },
{ _id: 626a15b5530afad2c5c18950, slug: 'bone', qty: 1 },
{ _id: 626a15c9530afad2c5c18951, slug: 'clam_shell', qty: 1 },
{ _id: 626a15d5530afad2c5c18952, slug: 'stone', qty: 8 },
{ _id: 626a15df530afad2c5c18953, slug: 'taeroot', qty: 1 },
{ _id: 626a15e9530afad2c5c18954, slug: 'shiny_pendant', qty: 1 },
{ _id: 626a15fd530afad2c5c18955, slug: 'sickleweed', qty: 1 },
{ _id: 626a1625530afad2c5c18956, slug: 'ceruleaf', qty: 1 },
{ _id: 626a1dba272403ea21fb71ef, slug: 'stone', qty: 1 },
{ _id: 626a1e4030a144f8179789e0, slug: 'birch_log', qty: 22 }, <- IMPORTANT
{ _id: 626a1e72372733f90cfdc003, slug: 'tree_twig', qty: 2 },
{ _id: 626a1e9a372733f90cfdc004, slug: 'honey', qty: 2 }
],
...
where you can see that my birch_log qty is now at 22. But whenever I go check in the database,
I don't know what's going on, and I'm kind of tired right, so I'll go to bed hoping someone can save me tomorrow :)
Thanks and have a good night ! :)
To update the object having {slug: birch_log}, you can use the following query:
player.update( {user : 123456 , inventory.slug : "birch_log" } ,
{$inc : {"inventory.$.qty" : 1} });
instead of using save() with promise, you can use update() query with async await. It will be short and clean code.
This answer fixed my problem
Since i'm using an "anonymous" array or whatever, mongoose doesn't know what changes to track in it so I need to tell it that it's been modified !
I'm trying to work on my Stripe Checkout Session, by passing an array of product data to the backend node.js server, and iterate over it.
I have my object of products like:
{
products: [
{
_id: '62129d5184689c5c77eb8fed',
title: 'GBOS Champion Tie Die Hoodie',
description: 'Tie die has never looked better with this new style of hoodies from the collection',
image: 'http://cdn.shopify.com/s/files/1/0002/9061/9452/products/unisex-champion-tie-dye-hoodie-navy-front-60831f17ab838_1200x1200.png?v=1619205920',
categories: [Array],
sizes: [Array],
color: '',
price: 54,
createdAt: '2022-02-20T19:58:09.071Z',
updatedAt: '2022-02-20T19:58:09.071Z',
__v: 0,
quantity: 1,
size: ''
},
{
_id: '62129d5184689c5c77eb8fed',
title: 'GBOS Champion Tie Die Hoodie',
description: 'Tie die has never looked better with this new style of hoodies from the collection',
image: 'http://cdn.shopify.com/s/files/1/0002/9061/9452/products/unisex-champion-tie-dye-hoodie-navy-front-60831f17ab838_1200x1200.png?v=1619205920',
categories: [Array],
sizes: [Array],
color: '',
price: 54,
createdAt: '2022-02-20T19:58:09.071Z',
updatedAt: '2022-02-20T19:58:09.071Z',
__v: 0,
quantity: 1,
size: ''
},
{
_id: '62129d5184689c5c77eb8fed',
title: 'GBOS Champion Tie Die Hoodie',
description: 'Tie die has never looked better with this new style of hoodies from the collection',
image: 'http://cdn.shopify.com/s/files/1/0002/9061/9452/products/unisex-champion-tie-dye-hoodie-navy-front-60831f17ab838_1200x1200.png?v=1619205920',
categories: [Array],
sizes: [Array],
color: '',
price: 54,
createdAt: '2022-02-20T19:58:09.071Z',
updatedAt: '2022-02-20T19:58:09.071Z',
__v: 0,
quantity: 1,
size: ''
},
{
_id: '62129d5184689c5c77eb8fed',
title: 'GBOS Champion Tie Die Hoodie',
description: 'Tie die has never looked better with this new style of hoodies from the collection',
image: 'http://cdn.shopify.com/s/files/1/0002/9061/9452/products/unisex-champion-tie-dye-hoodie-navy-front-60831f17ab838_1200x1200.png?v=1619205920',
categories: [Array],
sizes: [Array],
color: '',
price: 54,
createdAt: '2022-02-20T19:58:09.071Z',
updatedAt: '2022-02-20T19:58:09.071Z',
__v: 0,
quantity: 1,
size: ''
}
]
}
and it is sent via the React.js front-end through:
const handleStripe = async () => {
const res = await fetch("http://localhost:5000/api/stripe/checkout", {
method: "POST",
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
products: cart.products
}),
});
}
I want to, in the node.js backend, iterate through each of the products and add them to the line items array Stripe needs, essentially like this:
router.post("/checkout", async (req, res) => {
const products = req.body;
const session = await stripe.checkout.sessions.create({
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: 'T-shirt',
},
unit_amount: 2000,
},
quantity: 1,
},
{
price_data: {
currency: 'usd',
product_data: {
name: 'Mug',
},
unit_amount: 500,
},
quantity: 1,
}
],
mode: 'payment',
success_url: 'http://localhost:3000/',
cancel_url: 'http://localhost:3000/cart',
});
res.redirect(303, session.url);
});
I keep getting products.map, products.forEach, etc. is not a method.
Edit: The code for mapping
const products = req.body.products;
const items = products.map(product => {
return {
price_data: {
currency: 'usd',
product_data: {
name: product.name,
},
unit_amount: product.price * 100,
},
quantity: product.quantity,
};
});
The console prints out:
[
{
price_data: { currency: 'usd', product_data: [Object], unit_amount: 14599 },
quantity: 1
},
{
price_data: { currency: 'usd', product_data: [Object], unit_amount: 3599 },
quantity: 1
}
]
(node:5263) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'map' of undefined
It looks like you are trying to map over the body, not the products.
Instead of const products = req.body; do const products = req.body.products;. Supposing that you are using something like express.json() to transform the body into and object.
Say I have a data structure like so.
child: [
{
typeOfPackage: 'subSub',
parents: '/Test123/Diet/',
itemName: '250 ML',
pricePerItem: 150,
quantity: 0,
quantityType: '123',
description: '5',
avgTimeTaken: 0,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
_id: 617f9efdf0347931684888fd
},
{
typeOfPackage: 'sub',
parents: '/Test123/',
itemName: 'Regular',
pricePerItem: 0,
quantity: 0,
quantityType: '1',
description: '1',
avgTimeTaken: 1,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
_id: 617f9efdf0347931684888fe
},
{
typeOfPackage: 'subSub',
parents: '/Test123/Reg3/',
itemName: '500ML',
pricePerItem: 123,
quantity: 0,
quantityType: '12',
description: '123',
avgTimeTaken: 51,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
_id: 617f9efdf0347931684888ff
}
]
I intend to transform this data by splitting parents. And my intended result looks as follows:
child: [
{
itemName: 'Test123',
subPackages: [
{
itemName: 'Diet',
subSubPackages: [{
typeOfPackage: 'subSub',
parents: '/Test123/Diet/',
itemName: '250 ML',
pricePerItem: 150,
quantity: 0,
quantityType: '123',
description: '5',
avgTimeTaken: 0,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
}]
},
{
itemName: 'Regular',
typeOfPackage: 'sub',
parents: '/Test123/',
pricePerItem: 0,
quantity: 0,
quantityType: '1',
description: '1',
avgTimeTaken: 1,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
subSubPackages: [],
},
{
itemName: 'Reg3',
subSubPackages: [
{
typeOfPackage: 'subSub',
parents: '/Test123/Reg3/',
itemName: '500ML',
pricePerItem: 123,
quantity: 0,
quantityType: '12',
description: '123',
avgTimeTaken: 51,
images: [],
isEnabled: true,
inventory: [],
equipment: [],
_id: 617f9efdf0347931684888ff
}
]
},
]
}
]
I tried using lodash's chain and groupBy but I could only get as far as grouping it by the first itemName (Test123). I could not figure out how to do further grouping inside that without using a custom for loop and map methods and that too confused me.
You could split parents and build a nested structure.
This approach takes an shadow object for a faster access to same named parents and returns only the payload without organizing structure.
If you like to use subPackages or subSubPackages, you could take a function for generating this key along with the actuyl nesting level. For later processing data, I recommend to use only generic names, like children for every level.
const
getSub = level => `sub${'Sub'.repeat(level)}Level`,
data = [{ typeOfPackage: 'subSub', parents: '/Test123/Diet/', itemName: '250 ML', pricePerItem: 150, quantity: 0, quantityType: '123', description: '5', avgTimeTaken: 0, images: [], isEnabled: true, inventory: [], equipment: [], _id: '617f9efdf0347931684888fd' }, { typeOfPackage: 'sub', parents: '/Test123/', itemName: 'Regular', pricePerItem: 0, quantity: 0, quantityType: '1', description: '1', avgTimeTaken: 1, images: [], isEnabled: true, inventory: [], equipment: [], _id: '617f9efdf0347931684888fe' }, { typeOfPackage: 'subSub', parents: '/Test123/Reg3/', itemName: '500ML', pricePerItem: 123, quantity: 0, quantityType: '12', description: '123', avgTimeTaken: 51, images: [], isEnabled: true, inventory: [], equipment: [], _id: '617f9efdf0347931684888ff' }],
result = data
.reduce((r, o) => {
o
.parents
.split('/')
.filter(Boolean)
.reduce((t, itemName, i) => {
if (!t[itemName]) {
t[itemName] = { _: [] };
t._.push({ itemName, [getSub(i)]: t[itemName]._ });
}
return t[itemName];
}, r)
._
.push(o);
return r;
}, { _: [] })
._;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }