How to declare a static array in Node.js? - javascript

I am trying to create a static array named "categories" whom I wish it will be initialized ONCE in my Node.js application. I mean, when I close the app and run it again - I want it to KEEP the state of the "categories" array.
What happens is that the array is initialized for each time I run this app. Though I want it to be declared only once in this app's lifetime.
router.post("/add_category", (req, res, next) => {
var category = req.body.category;
categories.push(category);
res.render("index", { categories });
});

The simplest solution is to just write the array to a file as JSON and then load that back in when your server starts.
let categories = require('./categories.json');
router.post("/add_category", (req, res, next) => {
var category = req.body.category;
categories.push(category);
fs.writeFile(`./categories.json`, JSON.stringify(categories), () => {
res.render("index", { categories });
});
});
Node.js, by itself, does not have any automatically persisted variables that get saved to disk by themselves and are automatically available the next time you run the program. You have to code that yourself.

You should need a database for that kind of data persistence. But at times, a full-blown database (MongoDB, SQL) could be considered overkill since you only need to save a simple array.
So, consider using the "node-persist" package, here's a possible solution:
const storage = require('node-persist');
storage.initSync();
storage.setItem('categories', [ . . . ] );
console.log(storage.getItem('categories'));

That is was databases are for. Consider Using some SQL or noSQL database that will store values even if server is reseted.

Related

Is this a secure enough method to recover data?

I'd love to know if this method I'm using is secure enough to use on a public project, since I can't really find any other way to retrieve my id from my currently logged in user, but it's a fairly straightforward method , I find. If this method is not secure would it be possible to have a way to proceed? Thanks in advance.
I have a button for example when I use the send of the html that there is inside my div userid on the server to then use this information to make SQL queries from my app.js server.
I use socket.io hbs express node js jwt mysql
From my pages.js file generated with the express library where the main roads of my website are located, I send my user ID.
router.get('/accueil', authController.isLoggedIn, (req, res) => {
if(req.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});
With Handlebars I display this data in my index.hbs (display: none;).
<div id="iduser">{{data}}</div>
Then I get my iduser div on my client.js
let userid = document.getElementById('iduser').innerHTML;
// (My method to display this div)
socket.on('uid', (data) => {
pargent.innerHTML = JSON.stringify(data.data[0].argent);
})
//
So I want to use this userid variable to make SQL queries from my app.js.
(let userid = document.getElementById('iduser').innerHTML;)
I am using socket.io for communication between client and server to send my userid data
Example :
db.query('UPDATE users SET money = money + ? WHERE id = ?', [100, theUserId]);
No
Never trust user supplied data.
References:
https://www.oreilly.com/library/view/http-developers-handbook/0672324547/0672324547_ch22lev1sec1.html
https://flylib.com/books/en/1.290.1.90/1/
https://www.garybell.co.uk/never-trust-user-input/
https://medium.com/#berniedurfee/never-trust-a-client-not-even-your-own-2de342723674
https://www.invicti.com/blog/web-security/input-validation-errors-root-of-all-evil/
https://laravel-news.com/never-trust-your-users
https://www.wearenova.co.uk/nova-blog/when-it-comes-to-online-security-why-you-should-never-trust-a-client
It depends on your authController.isLoggedIn logic,
But I would like to suggest an alternative solution simple as that;
iron-session
Read their docs, it's matches your use case and easy to use; here is equivalent of the snippet you provided with iron session:
//initiate session middleware yourself
router.use(session)
// later here
router.get('/accueil', (req, res) => {
if(req.session.user) {
res.render('./accueil', {
data: req.user.id
});
} else {
res.redirect('/');
}
});

How to get data from back end side, to use it in the browser side?

I am new to programming, and I heard that some guys on this website are quite angry, but please don't be. I am creating one web app, that has a web page and also makes som ecalculations and works with database (NeDB). I have an index.js
const selects = document.getElementsByClassName("sel");
const arr = ["Yura", "Nairi", "Mher", "Hayko"];
for (let el in selects) {
for (let key in arr) {
selects[el].innerHTML += `<option>${arr[key]}</option>`;
}
}
I have a function which fills the select elements with data from an array.
In other file named: getData.js:
var Datastore = require("nedb");
var users = new Datastore({ filename: "players" });
users.loadDatabase();
const names = [];
users.find({}, function (err, doc) {
for (let key in doc) {
names.push(doc[key].name);
}
});
I have some code that gets data from db and puts it in array. And I need that data to use in the index.js mentioned above, but the problem is that I don't know how to tranfer the data from getData.js to index.js. I have tried module.exports but it is not working, the browser console says that it can't recognize require keyword, I also can't get data directly in index.js because the browse can't recognize the code related to database.
You need to provide a server, which is connected to the Database.
Browser -> Server -> DB
Browser -> Server: Server provides endpoints where the Browser(Client) can fetch data from. https://expressjs.com/en/starter/hello-world.html
Server -> DB: gets the Data out of the Database and can do whatever it want with it. In your case the Data should get provided to the Client.
TODOs
Step 1: set up a server. For example with express.js (google it)
Step 2: learn how to fetch Data from the Browser(Client) AJAX GET are the keywords to google.
Step 3: setup a Database connection from you Server and get your data
Step 4: Do whatever you want with your data.
At first I thought it is a simple method, but them I researched a little bit and realized that I didn't have enough information about how it really works. Now I solved the problem, using promises and templete engine ejs. Thank you all for your time. I appreciate your help)

MERN Stack: Can ExpressJs route add data from one Model to another Model's array attribute?

I hope I worded that correctly. Let me explain.
I'm creating an app where users can organize tournaments for a game (separate).
I'm creating this app with the MERN stack, with Redux as well.
I have numerous routes defined, for CRUD functionality and user authentication for example. My current workflow is to create the backend route, test it with Postman, and once it works I create the Redux reducer/action.
I have two data models. One is User, and one is Tournament.
Tournament model has a bunch of String type attributes like 'title', and one of it's attributes is 'participants' which is Array type.
I'm trying to write a Post request to a tournament/:id that contains the User.username, and push() that into Tournament.participants array.
I have tried multiple things but my current code looks like
router.post('/:id', (req, res) => {
Tournament.findById(req.params.id)
.then(tournament => tournament.participants.push(req.body))
.catch(err => res.json(err))
});
I am lost and could use help. Thanks all
This could work I think:
router.post('/:id', (req, res) => {
Tournament.findById(req.params.id)
.then(tournament => {
tournament.participants.push(req.body)
// save the updated tournament to the DB and take advantage of Promise-chaining
return tournament.save()
})
// send a response to the client
.then(savedTournament => res.json(savedTournament))
.catch(err => res.json(err))
});
You just need to make sure you save the updated tournament to the DB with this line:
return tournament.save()
Then, that will return a Promise which you can chain and then send off a response if successful. You were pulling the Model from the DB and updating the participants array, but then you need to store it in the DB and send a response to the client.

Is it safe to use a single Mongoose database from two files/processes?

I've been working on a server and a push notification daemon that will both run simultaneously and interact with the same database. The idea behind this is that if one goes down, the other will still function.
I normally use Swift but for this project I'm writing it in Node, using Mongoose as my database. I've created a helper class that I import in both my server.js file and my notifier.js file.
const Mongoose = require('mongoose');
const Device = require('./device'); // This is a Schema
var uri = 'mongodb://localhost/devices';
function Database() {
Mongoose.connect(uri, { useMongoClient: true }, function(err) {
console.log('connected: ' + err);
});
}
Database.prototype.findDevice = function(params, callback) {
Device.findOne(params, function(err, device) {
// etc...
});
};
module.exports = Database;
Then separately from both server.js and notifier.js I create objects and query the database:
const Database = require('./db');
const db = new Database();
db.findDevice(params, function(err, device) {
// Simplified, but I edit and save things back to the database via db
device.token = 'blah';
device.save();
});
Is this safe to do? When working with Swift (and Objective-C) I'm always concerned about making things thread safe. Is this a concern? Should I be worried about race conditions and modifying the same files at the same time?
Also, bonus question: How does Mongoose share a connection between files (or processes?). For example Mongoose.connection.readyState returns the same thing from different files.
The short answer is "safe enough."
The long answer has to do with understanding what sort of consistency guarantees your system needs, how you've configured MongoDB, and whether there's any sharding or replication going on.
For the latter, you'll want to read about atomicity and consistency and perhaps also peek at write concern.
A good way to answer these questions, even when you think you've figured it out, is to test scenarios: Hammer a duplicate of your system with fake data and events and see if what happen is OK or not.

Change database connection depending on route in express.js with sequelize

Is it possible to change the database connection in sequelize depending on the route?
For example, Users have access to 2 different installations in a website:
- example.com/foo
- example.com/bar
Upon login users are redirected to example.com/foo
To get all their tasks for the foo site, they need to visit example.com/foo/tasks
The bar site uses a separate database and thus if they want to get all their tasks for bar they have to go to example.com/bar/tasks
Every installation has its own database, and all databases have the same schema.
Is it possible to change the database connection depending on which route is visited?
*login only occurs once
This is possible. There are a number of ways to do this. Here's how I might approach it.
Router.js
var router = express.Router()
// This assumes the database is always the 2nd param,
// otherwise you have to enumerate
router.use('/:database/*', function(req, res, next){
req.db = req.params.database;
next();
}
Connection.js
var fooDB = new Sequelize('postgres://user:pass#example.com:5432/foo');
var barDB = new Sequelize('postgres://user:pass#example.com:5432/bar');
module.exports = {
foo: fooDB,
bar: barDB,
}
Tasks.js
var connection = require('connection);
function getTasks(req, params){
var database = connection[req.db];
//database now contains the db you wish to access based on the route.
}
That said, there are some interesting problems you'll have to face when you want to duplicate the schema across both, but that's probably best for another question.
I hope this helps!
I think is better to change collections depending on the route.
Have foo_tasks collection and bar_tasks collection in the same database.
Or have the attribute type in the tasks collection that specifies if the task is a "foo task" or a "bar task".

Categories