Collection.find() data not available outside function - javascript

I'm trying to get some data from my mongodb database to display it in a page. I'm using mongoose and expressjs. This is the code:
let cartData = {
game: []
}
let shoppingCart = Array.from(req.session.shoppingCart);
shoppingCart.forEach(e => {
Games.find({_id: e}, (err, data) => {
if (err) {
throw new Error(err);
} else {
cartData.game.push(data);
}
});
});
console.log(cartData)
res.render('carrito', cartData);
The problem is that the data fetched from the db inside the find() function is not "remaining" after each iteration of the forEach loop.
The shoppingCart Array contains game ids used to find the objects in the db.
Thanks in advance.

Related

Make a MySQL query reusable with double ?? for tables and ? for selectors with NodeJS and JavaScript

Hi. I am looking to create a reusable query with MySQL and NodeJS
The first step I took after the DB connection was to create a data access object and interact with the DB while using promises. To stay relative secure, I am using placeholders:
" ? " for rows and values and double " ?? " for tables.
I want to create functions to be reused. So if I am creating one function for insert, I need to use same function to insert records in different tables while using parameters.
The Data access layer looks like this: Here I am using parameters that will go to each function and replace the placeholders from the sql statements.
/*
Insert user accepts three parameters. Statement from mysql, table marked with ?? in the statement and the
payload object that have to match the database columns
*/
insertRecord: (sqlStatement, table, payload) => {
return new Promise((resolve, reject) => {
db.query(sqlStatement, [table, payload], (error, response) => {
if (error) return reject(error);
return resolve(response);
});
});
},
/*
This function accepts four parametters. The first parameter is the statement. Second parameter is the table selector
marked with ?? in the statement.
The selector is the row, and the value specified
*/
selectSimpleStatement: (sqlStatement, table, row, value) => {
return new Promise((resolve, reject) => {
db.query(sqlStatement, [table, row, value], (error, response) => {
if (error) return reject(error);
else return resolve(response);
});
});
}
}
The second implementation was to create all the MySQL queries separately because I wanted to keep it Clean
module.exports = {
insertStatement: 'INSERT INTO ?? SET ?',
sqlSimpleSelect: 'SELECT * FROM ?? WHERE ? = ?'
}
Using the first sql statement was easy. I worked to insert in all the tables with the same function. But the select is a pain. With postman I am getting empty arrays even if the values are correct...
const { sqlSimpleSelect } = require('../../database/statements.js');
const bcrypt = require('bcrypt');
exports.add = async (req, res, next) => {
const {username, password} = req.body;
try {
// Select from users where username = username variable
const user = await selectSimpleStatement(sqlSimpleSelect, 'users', 'username', username);
res.send(user);
}
catch (error) {
res.send(error)
}
}```
I am getting empty array. Can please help me?
Thanks, Daniel

How to Insert items into multiple Arrays in Node.js & MongoDB

This might be a weird question but I believe nothing is completely impossible.
I have a List of Users in MongoDB, each user has among other things, properties array which is currently empty.
In Excel sheet, I have a data that represents each user's properties which I want to programmatically insert in each user's properties array.
Importing excel sheet is fast and easy to populating each user's properties is what gives me the problem.
I have added userId, and PropeId, from the users and the properties they bought, so Identify them as seen below
router.put('/importdata', async (req, res)=>{
// upload queries
const imported = req.files.importdata;
const uploadpath = path.resolve(`public/excel_maneger/uploads/ ${imported.name}`);
if (imported.truncated) {
throw new Error("Uploaded File is too big, should not be morethan 20 MB");
}
await imported.mv(uploadpath);
const file = render.readFile(uploadpath);
const sheets = file.SheetNames;
const data = [];
for (let i = 0; i < sheets.length; i++) {
const sheetname = sheets[i];
const sheetData = render.utils.sheet_to_json(file.Sheets[sheetname]);
sheetData.forEach((item) => {
data.push(item);
});
}
try {
const users = await User.find({role: 'Customer'})
for(let i = 0; i < users.length; i++ ){
data.forEach((d) => {
if(users[i].id == d.id){
User.updateMany(
{},
{
$set: {
properties: {
propeId: d.propeId,
},
},
},
(err, d) => {
if (err) console.log(err);
}
);
}
});
}
} catch (err) {
console.log(err)
}
})
The Problem is that this code updates everyone on the Database (including non specified users) with the same information, Please I need help, I am trying to import 11 thousand users information from excel to database
When you are updating your User.updateMany(), You are not passing in the Id.
What it does is it when if statement is true, it updates all the user, You can use findByIdAndUpdate
Also you should be using async/await. Since that is what you are using to find the user
await User.findByIdAndUpdate( users[i]._id,{ $set: { properties: { propeId: d.propeId }}})
I have finally figured where I made the mistake, I am supposed to use $in: operator to access multiple Ids as desired.
Here's the solution:
data.forEach((d) => {
User.updateMany(
{ _id: { $in: [d.id] } },
{
$push: {
properties: d.propeId,
},
},
(err, d) => {
if (err) return false;
}
);
});
Above solved the problem amazingly

Node.js - Discord.js - Trying to navigate through a nested map. - UnhandledPromiseRejectionWarning

I've got a map, more specifically a Discord.Collection (which extends the normal javascript Map). The keys in that collection are the server id's the bot is part of. I want the values to be a list of other things, in my case a list of commands that should be blocked from use.
The values are in a map of themselves too, the console output of the nested maps is as follows:
Collection(1) [Map] {
'267975491477176321' => Promise {
Collection(2) [Map] {
'music' => 'music',
'roll' => 'roll'
}
}
}
How do I navigate through the second map in order to manipulate its values or grab them?
With
bot.bannedCmds.get(`${serverID}`)
I can easily grab the specific key of the first map.
The result:
Promise {
Collection(2) [Map] { 'music' => 'music', 'roll' => 'roll' }
}
But now when I try to, for example, do this:
if(bot.bannedCmds.get(`${serverID}`).has(`music`))
I get the error:
(node:28288) UnhandledPromiseRejectionWarning: TypeError: bot.bannedCmds.get(...).has is not a function
How do I work with this? Shouldn't the functions be available seeing how it is a Collection (Map) too? Or is that because it is within a Promise?
The function which fills the bot.bannedCmds Collection is:
exports.getBannedCmds = async function (serverID){
try{
let bannedCmds = new Discord.Collection();
let fetchBannedCmdsQuery = `SELECT * FROM bannedcmds WHERE serverID = '${serverID}'`;
let fetchBannedCmds = await db.query(fetchBannedCmdsQuery, function(err, result, fields) {
if (err) throw err;
let BlacklistTable = Object.assign(result);
for (var cmd in BlacklistTable) {
bannedCmds.set(`${BlacklistTable[cmd].cmd}`, `${BlacklistTable[cmd].cmd}`);
}
});
return bannedCmds;
} catch(error){
console.trace(error);
}
}
The function gets called inside the 'ready' event of the bot, in my main.js.
bot.bannedCmds.set(guild.id, TestFramework.getBannedCmds(guild.id));

Can't change value of object variable that is a result of a query in Javascript / ExpressJS / Mongodb

So I have the following code:
let addSubmissions = await Submission.find({"type": "add-information"}, (err) => {
if(err) {
console.log(err)
req.flash('error', 'No "add submissions" were found')
res.redirect('/admin')
}
})
for(let addKey in addSubmissions) {
let currentAddSubmissionAircraft = addSubmissions[addKey].aircraft
let addSubmissionAircraft = await Aircraft.findById(currentAddSubmissionAircraft, {name: 1}, (err) => {
if(err) {
console.log(err)
req.flash('error', 'No aircraft was found with the given ID')
res.redirect('/admin')
}
})
addSubmissions[addKey].aircraft = addSubmissionAircraft.name
}
I get all the submissions from the Submission collection in MongoDB and assign them to the addSubmissions variable. One of it's fields is 'aircraft' and it's value is an id from another collection called 'aircrafts'.
In the for loop I search the aircraft with the 'aircraft' field (which is the id) from the submissions and I want to change the value of 'addSubmissions.aircraft' from the id to the name of the aircraft.
For some reason the object is not changing.
Any idea why?
Thanks :)
You must to set in your function find, a method called lean().
Submission.find({}).lean().then()
There is another question: Can't add a new property to an object returned by Mongoose query

Save to database sequentially with NodeJS

I am trying to write a back-end in NodeJS for a newsreader app. The idea is to check a number of RSS feeds every few minutes, save new items to a database, and emit an event to connected users when a new item is added to the database.
I am having trouble writing a module which saves to the database. The desired behaviour is as follows:
Take the parsed RSS feeds, which are ordered in an array from newest to oldest, as input
For each item, starting with the newest, attempt to save it in the database
If the save was successful, log 'Save successful' to the console and attempt the next item
If the save fails, because the item already exists in the database, stop running the module.
The database model is already configured so the database does reject it when I try to save an item which already exists. However, the code below never logs the successful saves, and if I drop the database, it only saves the first document and then gives me a duplicate key error.
Any idea what I am doing wrong?
// Module
var { mongoose } = require('../db/mongoose');
var { Item } = require('../models/item');
var { scrape } = require('./scrape')
var { parse } = require('./parse')
var updateNewsDatabase = function() {
return new Promise((resolve, reject) => {
console.log('Scraping now')
scrape().then((rssFeeds) => {
var output = parse(rssFeeds);
saveEachNewsItem(output)
.catch((e) => {
console.log('Error:', e);
resolve()
})
})
});
}
async function saveEachNewsItem(newsItems) {
for (let item of newsItems) {
console.log('Attempting to save document')
var itemToSave = new Item(item);
await itemToSave.save()
.then((err, docs) => {
if (docs) {
console.log('Saved document to database')
}
if (err) {
throw new Error(err)
}
});
}
}
module.exports = { updateNewsDatabase }
In this part of your code, you are throwing exception and it makes it stop the for loop.
await itemToSave.save()
.then((err, docs) => {
if (docs) {
console.log('Saved document to database')
}
if (err) {
throw new Error(err)
}
});

Categories