Node js: fs WriteFile writing data to file twice - javascript

The fs.writeFile code in the backend is running twice.
The data appending appears in console twice and data is written twice in JSON file.
Any idea why this happens?
Any advice is greatly appreciated.
EDIT: this seems like a front-end problem. onFavSubmit is running twice...
Front-end
constructor (props) {
super (props)
this.state = {
inputOne: '',
chosenOne: ['Favourite Movie', 'X'],
chosenTwo: ['2nd Favourite Movie', 'X'],
chosenThree: ['3rd Favourite Movie', 'X'],
movies:[],
};
this.onFavSubmit = this.onFavSubmit.bind(this);
this.onReset = this.onReset.bind(this);
}
onFavSubmit = event => {
const newFav = {
first: this.state.chosenOne[0],
second: this.state.chosenTwo[0],
third: this.state.chosenThree[0]
}
if(this.state.chosenOne[1] === 'X' || this.state.chosenTwo[1] === 'X' || this.state.chosenThree[1] === 'X'){
alert ('Need All 3 Favourite Shows')
event.preventDefault();
} else {
axios.post('http://localhost:8001/fav', {newFav})
.then(
alert('Successfully Added'),
this.onReset()
)
.catch(err => console.log(err.response))
}
}
<button className="fav__button" type="button" onClick={this.onFavSubmit}>Click Me</button>
Back-end
const express = require("express");
const favData = require("../data/fav.json")
const fs = require ('fs')
const router = express.Router();
router.get("/", (_, res) => {
res.json(favData);
});
router.post("/", (req, res) => {
const newFirst = req.body.newFav.first;
const newSecond = req.body.newFav.second;
const newThird = req.body.newFav.third;
const newfavData = {
First: newFirst,
Second: newSecond,
Third: newThird,
};
fs.readFile('./data/fav.json', 'utf-8', function (err, data){
var json = JSON.parse(data);
json.push(newfavData);
console.log(newfavData)
fs.writeFile('./data/fav.json', JSON.stringify(json), function(err){
if (err) throw err;
console.log('data appended')
return;
})
})
});
module.exports = router;

I don't have enough reputation so I can't comment.
Have you tried commenting out this.onReset() and see if that fixes the problem?
There had been times when I was sending a request to "/" on reload.

Related

TypeError deleting a file with gridfs mongoose and node.js

I am developing an application that allows uploading and downloading music.
I can upload files, send them to the client... however, I have problems when it comes to deleting a bucket file...
I'am using "mongoose": "^6.2.1".
My controller, where podcastId is a ObjectId:
const connection = require('../database')
const mongoose = require('mongoose')
const Users = require('../models/Users')
const PodcastInfo = require('../models/PodcastInfo')
ctrPod.deletePodcast = async (req, res, next) => {
try {
const id = req.params.idPodInfo
const info = await PodcastInfo.findById(id)
const { userId, podcastId } = info
const gridFsBucket = new mongoose.mongo.GridFSBucket(connection, {
bucketName: 'podcasts',
});
gridFsBucket.delete(podcastId, (err) => {
console.log(err)
})
.
.
.
I get this error:
TypeError: Cannot use 'in' operator to search for 'client' in undefined
at getTopology
The problem appears here, \node_modules\mongodb\lib\utils.js:363:23) :
function getTopology(provider) {
if (`topology` in provider && provider.topology) {
return provider.topology;
}
else if ('client' in provider.s && provider.s.client.topology) {
return provider.s.client.topology;
}
else if ('db' in provider.s && provider.s.db.s.client.topology) {
return provider.s.db.s.client.topology;
}
throw new error_1.MongoNotConnectedError('MongoClient must be connected to perform this operation');
}
////////////////////////
delete(id, callback) {
return (0, utils_1.executeLegacyOperation)((0, utils_1.getTopology)(this.s.db), _delete, [this, id, callback], {
skipSessions: true
});
}
/////////////////////////////////////
What am I doing wrong?
I think the problem lies here:
const gridFsBucket = new mongoose.mongo.GridFSBucket(connection, {
bucketName: 'podcasts',
});
new mongoose.mongo.GridFSBucket(db,{bucketName}) takes in a db not a connection. Try:
const gridFsBucket = new mongoose.mongo.GridFSBucket(connection.db, {
bucketName: 'podcasts',
});

How to make a model in another file

I'm beginner and tried to transfer the model to another file, it didn't work for me, suggest me how to do it correctly. The question may seem silly, but if I knew the answer, I would not ask it.
file todo.controller.js
const fs = require("fs");
const { v4: uuidv4 } = require("uuid");
const data = fs.readFileSync("./data/data.json");
let todos = JSON.parse(data);
class todoController {
async createTodo(req, res) {
req.on("data", (data) => {
const jsondata = JSON.parse(data);
const title = jsondata.title;
const description = jsondata.description;
if ((title, description)) {
todos.push({
id: uuidv4(),
title,
description,
dateOfCreate: new Date(),
lastModified: new Date(),
check: new Boolean(false),
});
fs.writeFile(
"./data/data.json",
JSON.stringify(todos, null, 2),
(err) => {
if (err) throw error;
}
);
}
});
}}
file todo.router.js
const url = require("url");
const todoController = require("../controllers/todo.controller");
const todoRouter = (req, res) => {
const urlparse = url.parse(req.url, true);
if (urlparse.pathname == "/todos" && req.method == "POST") {
todoController.createTodo(req, res);
}
};
module.exports = todoRouter;
here is file data.json
data.json
You have two separate problems here, separating your code to a different file and also saving or persisting that data somewhere, in this case a file.
You have to create something like a data model and then you have to import it in your other code.
// data.js
export const get = async () => {} // we will implement this just now
export const set = async (data) => {} // we will implement this just now
...
// controller.js
import {get, set} from './data.js' // import the methods we just created
...
const createTodo = async (req, res) => {
req.on("data", (data) => {
// here you can use get() if you want to use the data
set(JSON.stringify(data)) // send data to your data model
}
}
Then we also have to actually do something with those methods.
// data.js
export const get = async () => {
// may need to use JSON.parse here depending on how you'll use it
return fs.readFile('./data.json')
}
export const set = async (data) => {
fs.writeFile('data.json', JSON.stringify(data))
}
So the idea is to have a model responsible for managing the data, retrieving it and saving it, then importing and using those methods in the main controller. The code above isn't perfect, it's just to show you how to think about it.

Encountering a problem when trying to remove some code from a route to put it into a service - Node.js / Express.js

I'm having a problem right now when i want to remove some code out of my route to put it into a service. I'm just trying to follow the best practices of developing an application.
This is my route right now:
const express = require('express');
const cityRouter = express.Router();
const axios = require('axios');
const NodeCache = require('node-cache');
const myCache = new NodeCache();
cityRouter.get('/:cep', async (request, response) => {
try {
const { cep } = request.params;
const value = myCache.get(cep);
if (value) {
response.status(200).send({
city: value,
message: 'Data from the cache',
});
} else {
const resp = await axios.get(`https://viacep.com.br/ws/${cep}/json/`);
myCache.set(cep, resp.data, 600);
response.status(200).send({
city: resp.data,
message: 'Data not from the cache',
});
}
} catch (error) {
return response.status(400);
}
});
module.exports = cityRouter;
I'm using axios to retrieve data from an API, where i have a variable called "cep" as a parameter and then using node-cache to cache it.
And it works with out problems:
enter image description here
But, when i try to put the same code into a service, and then call it into my route:
My service:
const axios = require('axios');
const NodeCache = require('node-cache');
const myCache = new NodeCache();
function verificaCache(cep) {
return async function (request, response, next) {
const value = myCache.get(cep);
console.log(cep);
if (value) {
response.status(200).send({
city: value,
message: 'Data from the cache',
});
} else {
const resp = await axios.get(`https://viacep.com.br/ws/${cep}/json/`);
myCache.set(cep, resp.data, 600);
response.status(200).send({
city: resp.data,
message: 'Data not from the cache',
});
}
next();
};
}
module.exports = verificaCache;
My route using the service:
const express = require('express');
const cityRouter = express.Router();
const verificaCache = require('../services/VerificaCacheService');
cityRouter.get('/:cep', async (request, response) => {
const { cep } = request.params;
verificaCache(cep);
response.status(200);
});
module.exports = cityRouter;
By some reason, it doesn't work:
enter image description here
What is the problem that i can't see? I'm a beginner so i'm kinda lost right now.
You have created a high-order function by returning a function in verificaCache(), so to properly call it you need to do it like that await verificaCache(cep)(req, res), remember, the first time you call it, you have a function being returned, since you want the tasks inside of that function to be executed, you need to call it as well.
Take a reading about high-order functions here: https://blog.alexdevero.com/higher-order-functions-javascript/
My recommendation, you could just get rid of the other function you are returning to simplify your code, and let the service only handle business logic, all the http actions should be handled on the controller level:
// Service
function verificaCache(cep) {
const value = myCache.get(cep);
if (value) {
return { city: value, message: 'Data from the cache'})
}
// No need of an else statement because the
// execution will stop at the first return if the condition passes
const resp = await axios.get(`https://viacep.com.br/ws/${cep}/json/`);
myCache.set(cep, resp.data, 600);
return { city: resp.data, message: 'Data not from the cache'};
}
// Controller
cityRouter.get('/:cep', async (request, response) => {
const { cep } = request.params;
try {
const data = verificaCache(cep);
// Use json() instead of send()
response.status(200).json(data);
} catch(error) {
// Handle errors here
console.log(error);
}
});
Estamos juntos!

Problem with parsing data at filestream and cvparser

I'm having a problem reading this piece of code in a project that we are developing with colleagues. I'll be greateful if you can help me and tell me what that piece of code mean. I get that in that piece, I`m having the technologies.csv file and we need to parse it, and if there is an error we must throw an exception to this error. And at the end of the code there are some cards but i don't know what is the idea of this cards. And at the final we have to export the module with the data, and i think the data is from the const with the programing languages.If someone can explain it with details it would be more than perfect. Thanks in advance! :)
const fs = require('fs');
const parse = require('csv-parse');
const path = require('path');
const constants = {
testData: {
csvColumns: [
'ruby',
'python',
'vuejs',
'angular',
'react',
'nodejs',
],
},
};
const configFileLocation = (name) => {
return
{
filename: path.join(__dirname, `${name}technologies.csv`)
}
}
const getData = (name) =>
new Promise((resolve, reject) => {
const fileLocation = configFileLocation(name).filename;
const csvParser = parse({
delimiter: ',',
});
if (!fs.existsSync(fileLocation)) {
reject(new Error(`File ${fileLocation} is missing.`));
}
const csvFileStream = fs.createReadStream(fileLocation);
csvFileStream.on('ready', () => {
csvFileStream.pipe(csvParser);
});
csvFileStream.on('error', (error) => {
reject(
new Error({
error,
message: 'csvParseCards#csvFileStream on error',
})
);
});
csvParser.on('error', (error) => {
reject(
new Error({
error,
message: 'csvParseCards#csvParser on error',
})
);
});
const cards = [];
csvParser.on('readable', () => {
let record = '';
while ((record = csvParser.read())) {
const card = {};
const columns = constants.testData.csvColumns;
if (record.length !== columns.length) {
console.warn('Column mismatch', record);
}
record.map((value, index) => {
card[columns[index]] = value;
});
cards.push(card);
}
});
csvParser.on('end', () => {
cards.shift();
resolve(cards);
});
});
module.exports = getData;

Code not executed after PUT route using Express

I listen to the chat event of the tmijs library, upon the !overlay chat I want to execute some code. What I want to achieve upon getting that message is:
Fetch the user
Check if the user has enough currency
Deduct currency from the user
Trigger a socket event to my react app
Everything seems to work up until the last bullet point. In my terminal it's shown that my user gets currency (called 'kluiten' in my code) deducted, but all the code that comes after it doesn't get executed.
require('dotenv').config();
const PORT = process.env.PORT || 9000;
class TwitchAPI {
constructor({io}) {
this.io = io;
this.client = new tmi.client(options);
this.client.connect();
this.handleOverlayRequest = this.handleOverlayRequest.bind(this);
this.handleChatMessage = this.handleChatMessage.bind(this);
this.client.on('chat', this.handleChatMessage);
}
handleChatMessage (channel, userstate, message) {
if(message === '!overlay') this.handleOverlayRequest(channel, userstate);
}
async handleOverlayRequest (channel, userstate) {
const requiredKluiten = 5;
const rawFoundUser = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}`);
const foundUser = await rawFoundUser.json();
if(foundUser.instakluiten >= requiredKluiten) {
this.client.action(channel, `${userstate[`display-name`]}, you've got enough instakluiten for this.`);
const method = `PUT`;
const payload = { 'requiredKluiten': requiredKluiten };
const body = JSON.stringify(payload);
const headers = { 'Content-Type': `application/json; charset=utf-8` };
const result = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}/decrementKluiten`, { method, body, headers });
console.log(result);
}
}
}
module.exports = TwitchAPI;
I then have an Express router:
const express = require('express');
const userController = require('../controllers/userController');
const router = express.Router();
router.route('/users/:username/decrementKluiten').put(userController.decrementKluiten);
router.route('/users/:username').get(userController.getUser);
router.route('/overview').get(userController.getOverview);
module.exports = router;
which makes sure the currency gets deducted. What I'm stuck on now is that, after all this has happened, I can't execute any code anymore after the fetch. I found though that I could execute code by resolving the promise in my route, but that feels really dirty and messes up my split up files:
router.route('/users/:username/decrementKluiten').put((req, res) => {
userController.decrementKluiten(req, res).then(x => {
console.log(x);
});
});
Is there a way to wait for my PUT to happen and still execute code after it did?
EDIT
userController.js
const {findChattersPerRole, getUserByUsername, decrementKluiten} = require('../actions');
const find = require(`lodash/find`);
const fetch = require(`isomorphic-fetch`);
const parseJSON = response => response.json();
module.exports = {
getUser: (req, res) => {
const username = req.params.username;
findChattersPerRole()
.then(chattersPerRole => {
const wantedUser = find(chattersPerRole, { username });
getUserByUsername(wantedUser.username)
.then(foundUser => {
if (foundUser) {
res.send(foundUser);
} else {
res.send(`No user has been found`);
}
});
});
},
getOverview: (req, res) => {
fetch(`https://tmi.twitch.tv/group/user/instak/chatters`)
.then(parseJSON)
.then(r => {
return res.json(r);
}).catch(err => {
console.log(err);
});
},
decrementKluiten: (req, res) => {
decrementKluiten(req.params.username, req.body.requiredKluiten);
}
}
actions.js
(Because this contains a lot of code I try to only include the relevant parts for this post, the database calls are done using Sequelize.js)
const decrementKluiten = (username, requiredKluiten) => {
return global.db.Viewer.findOne({
where: { username }
}).then(user => {
return user.decrement({ instakluiten: requiredKluiten });
});
};
module.exports = {
decrementKluiten
};
The issue is likely that you don't respond to the HTTP request in your /users/:username/decrementKluiten route. To solve this, change the exported decrementKluiten method in userController.js-file to this:
decrementKluiten: (req, res) => {
decrementKluiten(req.params.username, req.body.requiredKluiten)
.then(() => res.sendStatus(200))
.catch(() => res.sendStatus(500));
}
Some unrelated pointers to make your code a bit more readable, since you already use async functions in some parts of your code, but in other parts you interface directly with Promises.
The exported part of userController.js could utilize async functions:
module.exports = {
getUser: async (req, res) => {
try {
const username = req.params.username;
let chattersPerRole = await findChattersPerRole();
let wantedUser = find(chattersPerRole, { username });
let foundUser = await getUserByUsername(watnerUser.username);
if (foundUser) {
res.status(200).send(foundUser);
} else {
res.status(404).send('No user has been found');
}
} catch (e) {
res.sendStatus(500);
}
},
getOverview: async (req, res) => {
try {
let r = (await fetch('https://tmi.twitch.tv/group/user/instak/chatters')).json();
res.json(r);
} catch (e) {
res.sendStatus(500);
}
},
decrementKluiten: async (req, res) => {
try {
await decrementKluiten(req.params.username, req.body.requiredKluiten);
res.sendStatus(200);
} catch (e) {
res.sendStatus(500);
}
}
}
I've also added error handling in case something goes wrong, the server responds with a 500 Internal Server Error status code.
Judging by these lines in your TwitchAPI class:
const rawFoundUser = await fetch(`http://localhost:${PORT}/api/users/${userstate.username}`);
const foundUser = await rawFoundUser.json();
I assume you've tried to do const foundUser = await fetch('...').json(). This results in an error, but you can call the retuned value's methods and properties on the same line if you wrap the await expression in parentheses, like this:
const foundUser = await (await fetch('...')).json()`
If its methods does not return a Promise (i.e being synchronous), or you want to access a property, you can do:
const something = (await doSomethingAsync()).someMethod()
const somethingElse = (await doSomethingAsync()).property
I also noticed you're using template literals (backticks, `) for most strings without doing any template interpolation, which could simply be replaced with ' (single-quotes) or " (double-quotes).

Categories