How to save data using mongodb query in middleware in nodejs - javascript

I want to save data using mongodb query using middleware in node.js. please provide some code with example?

Try this. It works both for insert and update (upsert).
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const MongoClient = require('mongodb').MongoClient;
const mongodb_url = process.env.MONGO_URL || "mongodb://localhost:27017";
const mongodb_dbname = 'test_db';
const port = process.env.PORT || 3006;
const app = express();
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json({ extended: true}));
app.post('/api/post/:identifier', (req, res) => {
const identifier = req.params.identifier;
const content = req.body.payload;
MongoClient.connect(`${mongodb_url}`, { useNewUrlParser: true }, (err, client) => {
if (!err) {
let db = client.db(mongodb_dbname);
db.collection('posts')
.updateOne(
{ identifier: identifier },
{ $set: { content: content } },
{ upsert: true }
)
.then((output) => {
res.status(202).send({ message: "Sent"});
})
.catch((error) => {
res.status(500).send({
error_code: 500,
error_message: `Error while updating data - ${error}`
});
});
client.close();
} else {
res.status(500).send({
error_code: 500,
error_message: 'Error while connecting to database'
});
}
});
});
app.listen(port, () => {
console.log(`API bootstrapped on port ${port}...`);
});
Use the following package.json file:
{
"name": "mongo-upsert",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"mongodb": "^3.6.0"
}
}
When invoked as localhost:3006/api/post/my-post with a request body containing:
{
"payload": "Hello world"
}
This code is going to upsert a MongoDB document like:
{
"_id" : ObjectId("5f3d272cbd52c9c109ea9baa"),
"identifier" : "my-post",
"content" : "Hello world"
}
Prerequisites for the above code to work:
To have a working installation of mongodb
To have a database named test_db
To have a collection named posts
In this example, we are adding a post content, identified by an identifier, which for the sake of simplicity I have added as a path param in the POST definition.
Install dependencies using npm install.
Run the app using npm start.
Good luck.

Look into W3Schools NodeJS MongoDB.
I don't have enough rep to comment so here's an answer.

Related

Alert box displaying 'undefined' instead of success message

I'm building a server-side rendered website with Node. I want to display a green alert box upon successfully updating data in updateSettings.js. Even though the user data (name and email) is updated on Compass correctly, I get a red alert box (error) with undefined as the message. In the browser console, I get a 'bad request' error from bundle.js.
Also, no code seems to run after the Axios PATCH request code
updateSettings.js
/* eslint-disable */
import axios from 'axios';
import { showAlert } from './alerts';
export const updateData = async (name, email) => {
try {
const res = await axios({
method: 'PATCH',
url: 'http://127.0.0.1:3000/api/v1/users/updateMe',
data: {
name,
email,
},
});
if (res.data.status === 'success') {
showAlert('success', 'Data updated successfully!');
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
Alerts.js
/* eslint-disable */
export const hideAlert = () => {
const el = document.querySelector('.alert');
if (el) el.parentElement.removeChild(el);
};
// type is 'success' or 'error'
export const showAlert = (type, msg) => {
hideAlert();
const markup = `<div class="alert alert--${type}">${msg}</div>`;
document.querySelector('body').insertAdjacentHTML('afterbegin', markup);
window.setTimeout(hideAlert, 5000);
};
Index.js
`
/* eslint-disable */
import '#babel/polyfill';
import { login, logout } from './login';
import { displayMap } from './leaflet';
import { updateData } from './updateSettings';
// DOM ELEMENTS
const leaflet = document.getElementById('map');
const loginForm = document.querySelector('.form--login');
const logOutBtn = document.querySelector('.nav__el--logout');
const updateDataForm = document.querySelector('.form-user-data');
// DELEGATION
if (leaflet) {
const locations = JSON.parse(leaflet.dataset.locations);
displayMap(locations);
}
if (loginForm)
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const password = document.getElementById('password').value;
const email = document.getElementById('email').value;
login(email, password);
});
if (logOutBtn) logOutBtn.addEventListener('click', logout);
if (updateDataForm)
updateDataForm.addEventListener('submit', (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
updateData(name, email);
});
`
Running the node debugger indicates that process.env.NODE_ENV is undefined but I'm using dotenv for this so it should be working just fine. In any case, the login functionality which is quite similar and uses axios runs just fine.
App.js
const path = require('path');
const express = require('express');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const cookieParser = require('cookie-parser');
// eslint-disable-next-line node/no-deprecated-api
const exp = require('constants');
const AppError = require('./utilities/appError');
const globalErrorHandler = require('./controllers/errrorController');
const tourRouter = require('./routes/tourRoutes');
const userRouter = require('./routes/userRoutes');
const reviewRouter = require('./routes/reviewRoutes');
const viewRouter = require('./routes/viewRoutes');
const app = express(); //express is a function which upon calling will add a bunch of methods to the app variable
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
// 1.GLOBAL MIDDLEWARES
// Serving static files
// app.use(express.static(`${__dirname}/public`));
app.use(express.static(path.join(__dirname, 'public')));
// Set Security HTTP headers
app.use(helmet());
// Development logging
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'development') {
// the readinng of the process only needs to happen once, and the process is the same no matter which file we're in
app.use(morgan('dev'));
}
// Limit requests from same API
const limiter = rateLimit({
max: 100,
windowMs: 60 * 60 * 1000,
message: 'Too many requests from this IP, please try again in an hour',
});
app.use('/api', limiter);
// Body parser: reading data from body into req.body
app.use(express.json({ limit: '10kb' })); //'express.json' here is middleware
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser());
// Data sanitization against NoSQL query injection
app.use(mongoSanitize());
// Data sanitization agains XSS
app.use(xss());
// Prevent parameter pollution
app.use(
hpp({
whitelist: [
'duration',
'ratingsAverage',
'ratingsQuantity',
'maxGroupSize',
'difficulty',
'price',
],
})
);
// Test middleware
app.use((req, res, next) => {
// we have access to the requestTime property; assuming we want to display the time of the request
req.requestTime = new Date().toISOString();
next();
console.log(req.cookies);
});
// 3. ROUTES: this is where we mount our routers
// these 3 routers are actually middlewares that we mount upon the paths
app.use('/', viewRouter); //mounted right on the root URL
app.use('/api/v1/tours', tourRouter); //we've created a sub-app with this
app.use('/api/v1/users', userRouter);
app.use('/api/v1/reviews', reviewRouter);
// this router is essentially a sub-app for each resource
// the request goes into middleware and when it hits the above line of code, it will match the url, and thus the tourRouter middleware function will run
app.all('*', (req, res, next) => {
next(new AppError(`Cant find ${req.originalUrl} on this server!`, 404));
});
app.use(globalErrorHandler);
module.exports = app;
/updateMe
exports.updateMe = catchAsync(async (req, res, next) => {
// 1) Create error if user POSTs password data
if (req.body.password || req.body.passwordConfirm) {
return next(
new AppError(
'This route is not for password updates. Please use /updateMyPassword',
400
)
);
}
// 2) Filter out unwanted field names that are not allowed to be updated
const filteredBody = filterObj(req.body, 'name', 'email');
// 3) Update user document
const updatedUser = await User.findByIdAndUpdate(req.user.id, filteredBody, {
new: true,
runValidators: true,
});
res.status(400).json({
status: 'success',
data: {
user: updatedUser,
},
});
});
package.json
"scripts": {
"start": "nodemon server.js",
"start:prod": "NODE_ENV=production nodemon server.js",
"debugger": "ndb server.js",
"watch:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js",
"build:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js"
},
"author": "Dave Odipo",
"license": "ISC",
"dependencies": {
"#babel/polyfill": "^7.12.1",
"axios": "^1.1.3",
"b": "^2.0.1",
"babel": "file:../../../../../../../../polyfill",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.6",
"dotenv": "^16.0.2",
"express": "^4.18.1",
"express-mongo-sanitize": "^2.2.0",
"express-rate-limit": "^6.6.0",
"helmet": "3.16",
"hpp": "^0.2.3",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.13.15",
"morgan": "^1.10.0",
"nodemailer": "^6.8.0",
"pug": "^3.0.2",
"slugify": "^1.6.5",
"validator": "^13.7.0",
"xss-clean": "^0.1.1"
},
"optionalDependencies": {
"win-node-env": "^0.6.1"
},
"devDependencies": {
"eslint": "^8.23.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"parcel-bundler": "^1.12.3",
"prettier": "^2.7.1"
},
"engines": {
"node": ">=8.0.0"
}
}
Please help
Try changing res.status(400).json({ to res.status(200).json({

Why can't I connect to SQLServer uisng NodeJS?

I'm new using Node JS and now I'm creating a project that connects to SQL Server, but when I use the command node Database\connect.js It simply does do nothing, as it should do a console.log that it did connect or it didn't.
Here is my package.json
{
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"tedious": "^14.0.0"
},
"name": "weather-nodejs-apirest",
"version": "1.0.0",
"main": "connect.js",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
And here is my connect.js
var Connection = require('tedious').Connection;
var config = {
server: 'SERVERNAME',
authentication: {
type: 'default',
options: {
userName: 'sa',
password: 'password'
}
},
options: {
database: 'weather_app',
// instanceName: 'Sqlexpress',
rowCollectionOnDone: true,
useColumnNames: false
}
}
var connection = new Connection(config);
connection.on('connect', function (err) {
if (err) {
console.log(err);
} else {
console.log('Connected');
}
});
module.exports = connection;
The connection.on(...) method will not initiate the database connection itself. It only runs when the application initiates it using connection.connect() method.
Since you are exporting connection to the outside from connect.js, You should import and initiate the connection somewhere (mostly in application entry point),
const connection = require('path/to/connect.js');
// initiate
connection.connect();
Doc: http://tediousjs.github.io/tedious/getting-started.html

How to download multiple files bundled into one zip files in Node js?

I am working on node project, In my project I have two images in the images folder. Now my goal is I have to zip those two images and download. For this I am using this npm zip-downloader.
But I am getting these kind of errors
Error: Cannot find module 'babel-runtime/core-js/object/assign'
This is my code, server.js
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const multer = require('multer');
const upload = multer({dist:'./uploads'});
const jimp = require('jimp');
const zip = require('file-zip');
const downloader = require('zip-downloader')
app.post('/api/images',upload.single('profilepic'), (req, res) =>{
console.log(req.file)
res.json({'message':'file upload successfully'})
});
jimp.read('images/one.jpeg')
.then(one => {
return morng
.resize(100, 100) // resize
.quality(60) // set JPEG quality
.greyscale() // set greyscale
.write('images/two.jpg'); // save
})
.catch(err => {
console.error(err);
});
zip.zipFile(['images/one.jpeg','images/two.jpg'],'out.zip',function(err){
if(err){
console.log('zip error',err)
}else{
console.log('zip success');
}
})
const assets = [
{
'src': 'images/one.jpeg'
},
{
'src': 'images/two.jpg'
}
];
const options = {
downloadFolderName: 'images',
statusCallback: function(downloadedTillNow){
console.log('Download status:' + ((downloadedTillNow * 100)/assets.length));
},
onComplete : function(downloadedSummary){
console.log('Assets downloaded:' + downloadedSummary.numberOfDownloadedAssets);
console.log('Assets failed:' + downloadedSummary.numberOfFailedAssets);
console.log('Large Assets downloaded(over maxZIPSize):' + downloadedSummary.numberOfLargeUnZippedAssets);
console.log('Number of zip files downloaded:' + downloadedSummary.numberOfDownloadedZIPFiles);
console.log('Array of failed assets:');
console.log(downloadedSummary.failedAssetList);
},
};
downloader(assets, options);
This is package.json file
{
"name": "file",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"file-zip": "^1.0.1",
"files-download-zip": "^3.1.1",
"jimp": "^0.9.3",
"jszip": "^3.2.2",
"multer": "^1.4.2",
"zip-downloader": "^1.0.2"
}
}
Need a solution to overcome this error.
Since you're defining an object const options = {}, all of the properties which are defined inside the bracket {} should follow by :
The error in this case:
SyntaxError: Invalid shorthand property initializer
means you're trying to create a property with invalid syntax.
You can fix it by:
const options = {
downloadFolderName: 'images',
statusCallback: function(downloadedTillNow){
console.log('Download status:' + ((downloadedTillNow * 100)/assets.length));
},
onComplete: function(downloadedSummary){
console.log('Assets downloaded:' + downloadedSummary.numberOfDownloadedAssets);
console.log('Assets failed:' + downloadedSummary.numberOfFailedAssets);
console.log('Large Assets downloaded(over maxZIPSize):' + downloadedSummary.numberOfLargeUnZippedAssets);
console.log('Number of zip files downloaded:' + downloadedSummary.numberOfDownloadedZIPFiles);
console.log('Array of failed assets:');
console.log(downloadedSummary.failedAssetList);
}
};

Heroku - specific route works locally but not on production

I have a node project which was deployed to an Heroku app.
The deploy was successful and i can open the app , but there is one route to which i'm getting a "Cannot GET" error (404) while other routes on the same page are working as expected.
Locally everything is working as expected and when i run heroku local in cmd i can see the response coming back from that function but i can't say the same for trying it from heroku app link.
server.js
'use strict';
var http = require ('http');
var url = require('url') ;
var express= require('express');
var app= express();
var port = process.env.PORT || 3000;
var mongoose = require ('mongoose');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect (db_details);
var conn=mongoose.connection;
var trip = require ('./Schemas/trip');
var user = require ('./Schemas/user');
app.all('/*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,accept,access_token,X-Requested-With');
next();
});
conn.on('error', function(err) {
console.log('connection error: ' + err);
process.exit(1);
});
conn.once('open',function() {
console.log('connected successfuly to the remote DB');
app.use(require('./Routes')); //API routings
app.listen(port);
console.log("listening on port "+port+" and waiting for WS requests");
});
Routes/api/trip.js
'use strict'
var router = require('express').Router();
var mongoose = require('mongoose');
var trip = require ('../../Schemas/trip');
var user = require ('../../Schemas/user');
var Gmap = require ('../../TripBuilder/builder');
// get all trips
router.get('/getTrips', function(req, res) {
trip.find({},'trip_id Trip_Name Country City', function(err, trips) {
res.send(trips.reduce(function(userMap, item) {
userMap[item.id] = item;
return userMap;
}, {}));
});
});
// create new trip
router.post('/addNewTrip', function(req, res,next) {
let newTrip = new trip ({"Trip_Id":req.body.Trip_id,"Trip_Name":req.body.Trip_Name,"Trip_Date":req.body.Trip_Date,
"Trip_Owner":req.body.Trip_Owner,
"Country":req.body.Country,"City":req.body.City,"status":"Pending","Days":[],"Sites":[]});
return newTrip.save().then(function(){
return res.send("A Trip was created");
}).catch(next);
});
router.post('/addUserToTrip', async function(req, res,next) {
user.find({'email':req.body.email},'first_name last_name email', function(err,obj) {console.log("print " +obj); });
let secUser = {"Trip_Id":req.body.Trip_id};
});
router.post('/createRoute', function(req, res,next) {
var map=new Gmap();
var origins = ['Big Ben, London, UK','Bridge St, Westminster, London SW1A 2JR, UK','Palace of Westminster, Westminster, London SW1A 0PW, UK','Whitehall, Westminster, London SW1A 2ET, UK'];
var destinations =['Big Ben, London, UK','Bridge St, Westminster, London SW1A 2JR, UK','Palace of Westminster, Westminster, London SW1A 0PW, UK','Whitehall, Westminster, London SW1A 2ET, UK'];
map.calcRoute(origins,destinations).then(function(result){
map.longestroute=result; //save start and end
origins.splice(origins.indexOf( map.longestroute.origin), 1);
origins.splice(origins.indexOf( map.longestroute.destination), 1);
map.waypoints=origins;
map.setRoute(map.longestroute.origin,map.longestroute.destination,map.waypoints).then(function(route){
return res.send(route);
});
}).catch(next);
});
module.exports = router;
Calling https://APP-NAME.herokuapp.com/api/trip/createRoute returns "Cannot GET /api/trip/createRoute", while calling https://APP-NAME.herokuapp.com/api/trip/getTrips returns a response.
Heroku logs seems to record the request without any special exceptions but nothing is coming back.
I added "res.send("ok");" inside "createRoute" just to see at least that will be sent back but nothing.
Package.json
"name": "tripin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"engines": {
"node": "9.8.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"#google/maps": "^0.4.6",
"body-parser": "^1.18.2",
"express": "^4.16.2",
"http": "0.0.0",
"https": "^1.0.0",
"inspect-process": "^0.5.0",
"mongoose": "^5.0.9",
"node-dev": "^3.1.3",
"package.json": "^2.0.1",
"request": "^2.85.0"
}
}
Thanks
Edit:
router.post('/createRoute) and router.get('/createRoute) were attempted.
didn't work in either case
Your error messages is complaining about the GET, so it wants to GET "createRoute".
The create route path is a POST (so your HTTP request should be a POST).
You can check this by implementing a GET, and give a response your will reconize..
router.get('/createRoute', function(req, res) {
// .. your reconizalbe response here ..
res.send("Oops I did a GET, but wanted to POST");
}
and/or test with tool which can invoke the POST, like Postman or some other tool.
Ok , so as we all know programming rules state that the smaller the issue is, the harder it is to find it.
I managed to find out the solution:
I had my project duplicated in heroku - once in the root folder and once in its folder like it should be.
That threw off any routing i tried.
cleaning up heroku and re-deploy did the trick.
Thank you all for trying to help

Record all remote calls in a nodejs express app for testing

The goal is to have recored api tests. This test are kind of integration tests, they load the whole app with all its middlewares and intercepts the external http calls and records them.
In Python world exists "WebTest" and "VCRPY" for that.
The app:
'use strict';
const express = require('express');
const request = require('superagent');
var app = express();
app.get('/hammer/version', function(req, res) {
request
.get('http://httpbin.org/get')
.end(function(err, response) {
console.log(response.body);
res.status(200).json({
version: '0.1.0',
url: response.body.url
});
});
});
module.exports = app;
The test:
/* global describe, it */
'use strict';
const request = require('supertest');
const app = require('./app.js');
var path = require('path');
var tape = require('tape');
var tapeNock = require('tape-nock');
// call tapeNock with tape and an options object
var test = tapeNock(tape, {
fixtures: path.join(__dirname, 'fixtures')
});
describe('Version test', function() {
this.timeout(0);
it('test version', function(done) {
test('record_version.json', function(t) {
request(app)
.get('/hammer/version')
.expect(200, {
url: "http://httpbin.org/get",
version: '0.1.0'
})
.end(function(err, res) {
if (err) return done(err);
t.end();
done();
});
});
});
});
The "package.json":
{
"name": "remote_node_test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"dependencies": {
"express": "^4.14.0",
"mocha": "^3.2.0",
"nock": "^9.0.2",
"superagent": "^3.3.1",
"supertest": "^2.0.1",
"tape": "^4.6.3",
"tape-nock": "^1.4.0"
},
"devDependencies": {
"mocha": "^3.2.0"
},
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC"
}
The test are run with "mocha":
NOCK_BACK_MODE=record node_modules/mocha/bin/mocha
First run works, second run with "lockdown/record" does not work.
The error:
% NOCK_BACK_MODE=lockdown node_modules/mocha/bin/mocha test.js :(
Version test
TAP version 13
# details.json
1) return current version
0 passing (32ms)
1 failing
1) Version test return current version:
TypeError: Cannot read property 'status' of undefined
at Test._assertStatus (node_modules/supertest/lib/test.js:263:10)
at Test._assertFunction (node_modules/supertest/lib/test.js:281:11)
at Test.assert (node_modules/supertest/lib/test.js:171:18)
at Server.assert (node_modules/supertest/lib/test.js:131:12)
at emitCloseNT (net.js:1553:8)
at _combinedTickCallback (internal/process/next_tick.js:71:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
Recorded are all requests, but i need only to record the "external" requests, and prevent "mocking/recording" my internal logic.
If you're using mocha, you may want to look for a similar nock/nockBack helpers that are mocha-specific (https://www.npmjs.com/search?q=mocha+nock)
That being said, you may also run into problems where the HTTP call supertest makes to the app gets picked up by nockBack.
I made a little example that uses only tape to do what you're trying to accomplish:
https://github.com/Flet/tape-nock-with-supertest-example
The afterRecord and before functions defined in setup-tape-nock.js are probably the secret sauce you would need even if using some other nockBack mocha helper.
Hope this helps!
One solution seems "replay" and configuring "passThrough" of requests to my local app.
/* global describe, it */
'use strict';
const request = require('supertest');
const app = require('./app.js');
var path = require('path');
const Replay = require('replay');
Replay.fixtures = __dirname + '/fixtures/replay';
Replay.passThrough('localhost', '127.0.0.1', '0.0.0.0');
describe('Version test', function() {
this.timeout(0);
it('test version', function(done) {
request(app)
.get('/hammer/version')
.expect(200, {
url: "http://httpbin.org/get",
version: '0.1.0'
})
.end(function(err, res) {
if (err) return done(err);
done();
});
});
});

Categories