use common function output in multple files in node.js - function

I am new to programming...still self learning. I have below problem
I have below code in x.js file which I wish to reuse in same x.js file as well as in y.js file. both x.js and y.js are in controllers folder in a node.js project. The code is
''''''''
let indexmain = function(){
async.parallel({branch_count(callback) {
Branch.countDocuments({}, callback); documents of this collection},
customer_instance_count(callback) {
CustInstance.countDocuments({}, callback);
},
customer_instance_available_count(callback) {
CustInstance.countDocuments({ status:'Interested' }, callback);
},
}
);
return [branch_count, customer_instance_count, customer_instance_available_count];
''''''''
When used in below code inthe same file:
''''''''
const { body, validationResult } = require("express-validator");
const Branch = require('../models/brdetails');
const Customer = require('../models/custdetails');
const CustInstance = require('../models/custInstance');
const async = require('async');
exports.index = (req,res) => { (
branch_count = Indexmain[0],
customer_instance_count = Indexmain[1],
customer_instance_available_count = Indexmain[2]);
(err, results, next) => { if (err) { return next(err); }
res.render('index.jade', {error: err, data: results });
}
};
'''
There is no error, but page does not load at all. When checked with
'''
console.log("Indexmain is", Indexmain[0]);
'''
Output is "Indexmain is undefined".
What is to be done? Please help.

Related

TypeError: Cannot read properties of undefined (reading 'filename') in multer

I have a very similar problem with respect to this fellow community contributor. How do i produce multer error message in my postman I followed through the comments made by other users and it was successful! However, when i tried to post a image that is a jpg formatted image( which i managed to do before the editing), it now fails and state that TypeError: Cannot read property 'filename' of undefined.
// multer.js file
successfully setup multer
**please tell me why this error comes on my code and give me a solution**
const multer = require('multer');
const storage = multer.diskStorage({
fileSize: 1024*1024*2,
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
cb(null, file.fieldname + '-' + uniqueSuffix)
}
})
const filter = function (req, file, cb) {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(new Error('unsupported files'), false)
}
}
var upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter : filter
});
module.exports = upload;
//controller.js file
//create function
here's my logic to create a new user
exports.create = (req, res, next) => {
if (!req.body) {
res.status(400).send({ message: "content cannot be empty !!" })
return
}
let data = { name: req.body.name, description: req.body.description, brand_url:
req.body.brand_url, image_file: req.body.file.filename }; getting error here
let sql = "INSERT INTO influencer SET ?";
db.query(sql, data, (err, results) => {
if (err) throw err;
console.log('data inserted succesfully')
res.redirect('/admin');
});
}
//api.js file
//post API
router.post('/api/create', upload.single('image') ,controller.create) //when I am
sending file its throw back error undefined filename
Please make sure you have added enctype="multipart/form-data"
<form action="/api/create" enctype="multipart/form-data" method="post">
I have tested the codes & found the problem.
exports.create = (req, res, next) => {
if (!req.body) {
res.status(400).send({ message: "content cannot be empty !!" })
return
}
let data = {
name: req.body.name,
description: req.body.description,
brand_url: req.body.brand_url,
image_file: req.file.filename
}; // Remove "body", I have tested, it works well.
let sql = "INSERT INTO influencer SET ?";
db.query(sql, data, (err, results) => {
if (err) throw err;
console.log('data inserted succesfully')
res.redirect('/admin');
});
}

How do I return an asynchronous DB query result from one module to another using Node.js?

I'm new to Node, and I'm trying to follow a pattern from a Udemy API course. The API is structured to utilize route, controller and service modules for flow. Database queries are to be run as services and they are supposed to be called from controllers.
I need to run a series of DB queries to generate a list (I'm showing only 2 of 6 queries in this example). I am running these using async/await in my function. The queries are working fine. My problem occurs when I try to return the 'batch result' (the result of all the queries) to the controller at the end of the process. I get Promise { <pending> }. I have tried many things, but I cannot end the promise to access the final result from my controller module--I can only access it from my service module.
Here is my code from my controller module (groups.controller.js) where I call my function:
const groupsService = require('../services/groups.service');
exports.propertyList = (req, res, next) => {
const uid = req.body.uid;
const batchResponse = groupsService.batchQuery(uid, res);
console.log(batchResponse);
}
And here is my code from my service module (groups.services.js) where I run the queries:
const mysql = require('mysql2');
const dbAsync = require("../config/db.config");
async function batchQuery(uid, res) {
var Q1;
var Q2;
var uid = uid * -1;
const pool = mysql.createPool(dbAsync.dbAsync);
const promisePool = pool.promise();
try {
Q1 = await promisePool.query('SELECT PropertyID FROM GroupMembership WHERE GroupID = ?', [uid]);
Q2 = await promisePool.query('SELECT SubGroupID FROM GroupMembership WHERE GroupID = ? AND PropertyID = ?', [uid, 0]);
}
catch(error) {
console.log(error);
res.status(401).send('Server error');
return error;
}
finally {
const batchResponse = {
Q1: Q1[0],
Q2: Q2[0]
}
console.log('Q1: '+ Q1[0][0].PropertyID + ', Q2: ' + Q2[0][0].SubGroupID);
res.status(200).send(batchResponse);
return batchResponse;
}
}
module.exports = {batchQuery};
When I send a post via postman, I get the expected query result (below). However, I can only get this to work if I put my res in my service module.
{
"Q1": [
{
"PropertyID": 0
}
],
"Q2": [
{
"SubGroupID": 397
}
]
}
Is there a way to end the promise in this pattern and return the desired batch response? Thank you.
EDIT: Adding the code updates provided by #traynor.
New controller:
const groupsService = require('../services/groups.service');
exports.propertyList = async (req, res, next) => {
const uid = req.body.uid;
let batchResponse;
try {
batchResponse = await groupsService.batchQuery(uid);
console.log(batchResponse);
return res.status(200).send(batchResponse);
} catch(error) {
console.log('Error: ' + error);
return res.status(401).send('Server error');
}
}
New service:
const mysql = require('mysql2');
const dbAsync = require("../config/db.config");
function batchQuery(uid) {
return new Promise((resolve, reject) => {
var Q1;
var Q2;
var uid = uid * -1;
const pool = mysql.createPool(dbAsync.dbAsync);
const promisePool = pool.promise();
try {
Q1 = await promisePool.query('SELECT PropertyID FROM GroupMembership WHERE GroupID = ?', [uid]);
Q2 = await promisePool.query('SELECT SubGroupID FROM GroupMembership WHERE GroupID = ? AND PropertyID = ?', [uid, 0]);
} catch(error) {
console.log(error);
reject(error);
} finally {
const batchResponse = {
Q1: Q1[0],
Q2: Q2[0]
}
console.log('Q1: '+ Q1[0][0].PropertyID + ', Q2: ' + Q2[0][0].SubGroupID);
resolve(batchResponse);
}
})
}
module.exports = {batchQuery};
the service is now returning a promise, and it's also handling response instead of controller.
to return from service, you need to promisify service: return a promise which resolves when you get db data, or on error, and then you also need to await the service, which it's wrapped in try/catch for error handling.
once it's all done, handle response from the controller:
service:
function batchQuery(uid) {
return new Promise(async (resolve, reject) => {
var Q1;
var Q2;
//...
try {
//...
} catch (error) {
console.log(error);
reject(error);
} finally {
const batchResponse = {
Q1: Q1[0],
Q2: Q2[0]
}
console.log('Q1: ' + Q1[0][0].PropertyID + ', Q2: ' + Q2[0][0].SubGroupID);
resolve(batchResponse);
}
});
controller:
exports.propertyList = async (req, res, next) => {
const uid = req.body.uid;
let batchResponse;
try {
batchResponse = await groupsService.batchQuery(uid);
console.log(batchResponse);
res.status(200).send(batchResponse);
} catch(error) {
return res.status(401).send('Server error');
}
}

req.file.stream is undefined

I'm having troubles with node 16 and ES6. I'm trying to make a upload file controller but i'm stuck with req.file.stream which is undefined
I'm using multer to handle upload files.
The first issue was __dirname undefined that I was able to fix with path and New Url.
The error I got with pipeline
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "source" argument must be of type function or an instance of Stream, Iterable, or AsyncIterable. Received undefined
my userRoutes.js
import express from "express";
import { signin, signup, logout } from "../Controller/AuthController.js";
import {
getUsers,
getUser,
updateUser,
deleteUser,
follow,
unfollow,
} from "../Controller/UserController.js";
import { upload } from "../Controller/UploadController.js";
import multer from "multer";
const router = express.Router();
// Auth
router.post("/signin", signin);
router.post("/signup", signup);
router.post("/logout", logout);
// users
router.get("/", getUsers);
router.get("/:id", getUser);
router.patch("/:id", updateUser);
router.delete("/:id", deleteUser);
router.patch("/follow/:id", follow);
router.patch("/unfollow/:id", unfollow);
// upload
router.post("/upload", multer().single("file"), upload);
export default router;
And my UploadController.js
import fs from "fs";
import { promisify } from "util";
import stream from "stream";
const pipeline = promisify(stream.pipeline);
// const { uploadErrors } = require("../utils/errors.utils");
import path from "path";
const __dirname = path.dirname(new URL(import.meta.url).pathname);
export const upload = async (req, res) => {
try {
// console.log(req.file);
console.log(__dirname);
if (
!req.file.mimetype == "image/jpg" ||
!req.file.mimetype == "image/png" ||
!req.file.mimetype == "image/jpeg"
)
throw Error("invalid file");
if (req.file.size > 2818128) throw Error("max size");
} catch (err) {
const errors = uploadErrors(err);
return res.status(201).json({ err });
}
const fileName = req.body.name + ".jpg";
await pipeline(
req.file.stream,
fs.createWriteStream(
`${__dirname}/../client/public/uploads/profil/${fileName}`
)
);
try {
await User.findByIdAndUpdate(
req.body.userId,
{ $set: { picture: "./uploads/profil/" + fileName } },
{ new: true, upsert: true, setDefaultsOnInsert: true },
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(500).send({ message: err });
}
);
} catch (err) {
return res.status(500).send({ message: err });
}
};
Multer gives you the file as a Buffer, not a Stream. req.file.stream is not valid property, but req.file.buffer is: https://github.com/expressjs/multer#file-information.
From the look of your code, you're trying to save the file on disk. You can use multer's DiskStorage for that. Create a storage instance and pass it to the multer instance as a configuration:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, `${__dirname}/../client/public/uploads/profil/`);
},
filename: function (req, file, cb) {
cb(null, req.body.name + '.jpg');
},
});
const upload = multer({ storage });
router.post('/upload', upload.single('file'), upload);
Have a look at this free Request Parsing in Node.js Guide for working with file uploads in Node.js.
if you want to use req.file.stream, you will need to install this version of multer:
npm install --save multer#^2.0.0-rc.1
and your code will work perfectly, just change your req.file.mimetype to req.file.detectedMimeType !!

Cannot read property 'findAll' of undefined sequelize

I'm a new learner to express js and sequelizejs. I successfully migrate table in my database so the connection is fine I guess.
Here is my code.
https://github.com/Picks42/express-test
Please review this file
https://github.com/Picks42/express-test/blob/master/models/user.js
Then review this one
https://github.com/Picks42/express-test/blob/master/controller/test.js
Let me know what's the issue.
// all the models using your index.js loader
const models = require('../models');
// the user model, note the capital User since
const M_Bank = models.User;
exports.getTest = function(req,res){
return M_Bank
.findAll()
// don't use M_Bank here since you are getting an array of Instances of the Model
.then(users => res.status(200).send(users))
.catch((error) => {
console.log(error.toString());
res.status(400).send(error)
});
/* this will never execute because it is after the return
exports.index = function (request, response, next) {
response.json((M_Bank.findAll()));
};
*/
};
If you have the option of using async/await it makes for more readable code.
const models = require('../models');
const M_Bank = models.User;
exports.getTest = async function(req, res) {
try {
const users = await M_Bank.findAll();
return res.status(200).send(users);
} catch (err) {
console.log(err.toString());
return res.status(400).send(err);
}
};
You should get rid of the .User field in the 3rd line. because you've exported User itself from the models/user file.
Also, I recommend you not to mess with variables names. M_Bank variable doesn't speak itself
const M_Bank = require('../models/user');
exports.getTest = function(req,res){
return M_Bank
.findAll()
.then(M_Bank => res.status(200).send(M_Bank))
.catch((error) => {
console.log(error.toString());
res.status(400).send(error)
});
exports.index = function (request, response, next) {
response.json((M_Bank.findAll()));
};
};

Getting file from hash in js-ipfs

I'm running the script below and using an ipfs node to upload and get a file using its hash, but the ipfs cat function only returns the path of the file from the hash, not the content.
const node = new Ipfs()
node.once('ready', () => console.log('IPFS node is ready'))
$("#saveIt").click(function(){
var toStore = document.getElementById('fileInput').value
node.files.add(new node.types.Buffer.from(toStore), (err, res) => {
if (err || !res) {
return console.error('ipfs add error', err, res)
}
res.forEach((file) => {
if (file && file.hash) {
var newVar = file.hash
var newVar1 = newVar.slice(0, 23)
var leng = newVar.length
var newVar2 = newVar.slice(24, leng)
console.log(newVar1 + ' ' + newVar2)
mediachain.setUserFile($("#passwordSetter").val(), newVar1, newVar2)
node.files.cat(file.hash, (err, data) => {
if (err) {
return console.error('ipfs cat error', err)
}
document.getElementById('fileDisplayArea').innerText = data
})
} else {
console.error("Error: invalid file")
}
})
})
})
Does anyone have experience with js-ipfs and can help me out?
I had a similar problem with ipfs.
if you have hash already you can get the content this way.
const validCID = 'QmQFPQ5f94byxs7zvHMLJcx5WzThRhN4MfAF4ZisSXofKC'
ipfs.files.get(validCID, function (err, files) {
files.forEach((file) => {
console.log(file.path)
console.log("File content >> ",file.content.toString('utf8'))
})
})