I'm trying to write a simple rest API to connect to my sql Server database and execute a simple query to retrieve data from a database.
I'm following this tutorial: https://medium.com/voobans-tech-stories/how-to-quickly-create-a-simple-rest-api-for-sql-server-database-7ddb595f751a
Here's where my confusion lies:
The example has a server initialization file that looks like this:
var express = require('express'); // Web Framework
var app = express();
var sql = require('mssql'); // MS Sql Server client
// Connection string parameters.
var sqlConfig = {
user: 'UserName',
password: 'mot de passe',
server: 'localhost',
database: 'DatabaseName'
}
// Start server and listen on http://localhost:8081/
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("app listening at http://%s:%s", host, port)
});
It also has a select query the example uses on the customer table located in the database:
app.get('/customers', function (req, res) {
sql.connect(sqlConfig, function() {
var request = new sql.Request();
request.query('select * from Sales.Customer', function(err, recordset) {
if(err) console.log(err);
res.end(JSON.stringify(recordset)); // Result in JSON format
});
});
})
What I'm not understanding is how these two files are connected or interacting. At the end of the tutorial, the author says in order to test the example, copy the code into a file and run it. The example has 4 separate files though - am I putting them all into the same document?
yes you can put all code snippets in the same file for your test. It will be the easiest way since they all using the app variable.
But if you want a bigger application, it's cleaner in multiple files. You can then use code from another file using an import like require('./filename.js');
Related
I'm having a play with the MEAN stack in order to teach myself a bit of javascript, and use Angular, and i'm having trouble setting up a MEAN environment.
I'm trying to connect to my Mongodb database, and read the contents of the "users" collection, which should contain two records, "John Doe", and "Jane Doe".
This is what my connection string looks like, as well as the constants I have at the top of the api.js
//Importing express, Router, Mongoclient and ObjectID
const express = require('express');
const router = express.Router();
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
//Connect
const connection = (closure) => {
//Connecting to "mongod://localhost" line, "/mean" is the name of the DB you
//want to connect too
return MongoClient.connect('mongodb://localhost:27017/mean', { useNewUrlParser: true }, (err, client) => {
if (err) return console.log(err);
var db = client.db('mean');
db.collection('users').findOne({}, function (findErr, result) {
if (findErr) throw findErr;
console.log(result.name);
client.close()
});
//closure(db);
});
};
When I run "node server" from the command line, it runs ok with no error:
C:\Users\jack_\OneDrive\Documents\code\mean>node server
Running on localhost:3000
However, when I try and navigate to "localhost:3000/api/users", nothing happens, the page gets stuck loading, and if I go back to the command line, it shows the first entry in "users":
C:\Users\jack_\OneDrive\Documents\code\mean>node server
Running on localhost:3000
John Doe
I can open the "localhost:3000/api" with no problem, and it takes me to the AngularJS landing page just fine.
I've had a read of over stackoverflow questions and found that there may be a problem with the mongodb driver, as they accidently released a beta version onto npm, so i checked my database version and the driver version:
C:\Users\jack_\OneDrive\Documents\code\mean>"C:\Program Files\MongoDB\Server\4.0\bin\mongod.exe" --version
db version v4.0.2
git version: fc1573ba18aee42f97a3bb13b67af7d837826b47
allocator: tcmalloc
modules: none
build environment:
distmod: 2008plus-ssl
distarch: x86_64
target_arch: x86_64
Database version:
C:\Users\jack_\OneDrive\Documents\code\mean>"C:\Program Files\MongoDB\Server\4.0\bin\mongo.exe" --version
MongoDB shell version v4.0.2
git version: fc1573ba18aee42f97a3bb13b67af7d837826b47
allocator: tcmalloc
modules: none
build environment:
distmod: 2008plus-ssl
distarch: x86_64
target_arch: x86_64
Looking at the other stackoverflow answers, because of the version I'm using, MongoClient.connect now returns a client object containing the database object
So I ammended the code with:
MongoClient.connect('mongodb://localhost:27017/mean', { useNewUrlParser: true }
and
var db = client.db('mean');
db.collection('users').findOne({}, function (findErr, result) {
if (findErr) throw findErr;
console.log(result.name);
client.close()
This got rid of my original error, which was "db.collections is not a function", but, according to the tutorial I'm following, I should see the contents of the "users" collection in a web browser, along with some other information, kinda like this:
{"status":200,"data":[{"_id":"598ce66bf7d6d70def3d9f6f","name":"John Doe"}
But, I'm not,
So what have I done wrong? or am I missing something, bearing in mind I was writing this at 3AM, so I more than likely missed something
Thanks in Advance
You can use below code to connect with db and find the data
const express = require('express');
const router = express.Router();
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/mean";
MongoClient.connect(url, function(err, client) {
if (err) throw err;
var db = client.db("mean");
db.collection("users").findOne({}, function(err, result) {
if (err) throw err;
console.log(result.name);
db.close();
});
});
I'm practicing right now with the MEAN stack.
I've made a project with the Angular shell and I've inclueded express in my project.
Here's my first GET, i want to use it to retrive some data from my mongoDB, in this case an entire collection:
router.get('/biscottigrazie', function(req, res) {
var db = req.db;
var collection = db.get('biscotti');
});
Maybe I'm missing the concept but i think that from angular i should be able to "call" this GET and get the data.
So, my var collection should contain the data, how can I retrive them from angular files?
You will not get db instance from request variable. You will get it while you define database.
var db = new Db('test', new Server('localhost', 27017));
router.get('/biscottigrazie', function(req, res) {
var collection = db.getCollection('biscotti');
res.send(collection);
});
I am using sails js with it sails-mssqlserver adapter. The problem with it is that if my stored procedure returns multiple result sets then I only receive one result set which is the latest of all.
The same stored procedure is working fine with Java and I get to iterate over the relevant result sets.
I need to know if there is some specific way to access all result sets in sails-mssqlserver?
The sails-mssqlserver adapter is a wrapper of the official Microsoft SQL Server client for Node.js available here its dependecy however is not on the latest release.
Option 1:
As per this official documentation of the MsSQL package, you can enable multiple recordsets in queries with the request.multiple = true command.
To enable multiple queries/recordsets in the sails-mssqlserver adapter, a hackish workaround is to open sails-mssqlserver/lib/adapter.js and edit the raw query function. Adding request.multiple = true below var request = new mssql.Request(mssqlConnect). As shown in the example below.
// Raw Query Interface
query: function (connection, collection, query, data, cb) {
if (_.isFunction(data)) {
if (debugging) {
console.log('Data is function. A cb was passed back')
}
cb = data
data = null
}
adapter.connectConnection(connection, function __FIND__ (err, uniqId) {
if (err) {
console.error('Error inside query __FIND__', err)
return cb(err)
}
uniqId = uniqId || false
var mssqlConnect
if (!uniqId) {
mssqlConnect = connections[connection].mssqlConnection
} else {
mssqlConnect = connections[connection].mssqlConnection[uniqId]
}
var request = new mssql.Request(mssqlConnect)
// Add it here
request.multiple = true
request.query(query, function (err, recordset) {
if (err) return cb(err)
if (connections[connection] && !connections[connection].persistent) {
mssqlConnect && mssqlConnect.close()
}
cb(null, recordset)
})
})
},
Now the returned recordset should contain multiple results.
Option 2:
A more sustainable option for use cases where running a stored procedure which returns multiple recordsets, is to use the latest version of the official Microsoft SQL Server client for Node.js. Information on running stored procedures is available here
First install the latest package:
npm install mssql --save
In your code where you would like to run the stored procedure add a connection to the mssql database:
// require the mssql package
const sql = require('mssql')
// make a connection, you can use the values you have already stored in your adapter
const pool = new sql.ConnectionPool({
user: sails.config.connections.<yourMsSQLConnection>.user,
password: sails.config.connections.<yourMsSQLConnection>.password,
server: sails.config.connections.<yourMsSQLConnection>.server,
database: sails.config.connections.<yourMsSQLConnection>.database
})
// connect the pool and test for error
pool.connect(err => {
// ...
})
// run the stored procedure using request
const request = new sql.Request()
request.execute('procedure_name', (err, result) => {
// ... error checks
console.log(result.recordsets.length) // count of recordsets returned by the procedure
console.log(result.recordsets[0].length) // count of rows contained in first recordset
console.log(result.recordset) // first recordset from result.recordsets
console.log(result.returnValue) // procedure return value
console.log(result.output) // key/value collection of output values
console.log(result.rowsAffected) // array of numbers, each number represents the number of rows affected by executed statemens
// ...
})
// you can close the pool using
pool.close()
In cases, where the sails-* database adapter doesn't include all the functionality you require. I find it best to create a sails Service that wraps the additional functionality. It is a really clean solution.
I am creating a csv file with node js and now want to download it to user's browser's default download location. We are using seneca with nodejs and csv file is getting saved on the server. Now when use will click export on the front end which angular based, node will create a csv and download that to user machine. How can we achieve this?
It is possible to download dynamic files generated with Node.js to the browser's default download location. There are many posts outlining how to retrieve static files from the server using the Express helper res.download(). Specific to your question there is a way to achieve what you are asking.
With interpretation of your question the following process is followed:
User generated data is sent to the server for processing when a user clicks export.
Node processes the data and generates a file that is to be downloaded without a second user interaction (user clicks Export and the file is downloaded).
Client
//Export button
$("#exportBtn").click(function () {
//Code to generate data for the CSV and save it to the src variable
var src = csvData;
//Send the CSV data to Node for processing and file generation.
$.post("http://localhost:3000/submitcsv", { csv: src }, function (data) {
//Check the returned file name in data - this check depends on your needs; ie: regex
if (data) {
//request the file that is to be downloaded to the client. Optionally use $window.open()
window.location.href = "http://localhost:3000/app/" + data;
}
});
});
Server
//Post data from the client
app.post('/submitcsv', function (req, res) {
var async = require('async');
var fs = require('fs');
var path = require('path');
var csvData = req.body.csv;
function processCSV(callback) {
//Code to create the csv file and a uniqueIdentifier
callback();
}
function finalize() {
//Save the CSV to the server. This is a specific location on the server in /app.
//You can use Express.static paths that suit your setup.
fs.writeFile('./app/temp/csvFile' + uniqueIdentifier + '.csv', buf, function (err) {
if (err) {
console.log(err);
res.send(500, "Something went wrong...");
}
else {
console.log("CSV file is saved");
//Send the file name and location back to the client
res.send('/temp/csvFile' + uniqueIdentifier + '.csv');
}
});
}
// After the CSV data is processed, save the file and send it to the client.
async.series([
processCSV
], finalize);
});
//Send the requested file back to the client
app.get('./app/:csvFile', function (req, res){
var c = req.params.csvFile;
res.download(c);
//Code to delete the file if it is temporary via fs.unlink
});
While it is not shown in the above code for simplicty, it is recommended that the /app routes sending and receiving this type of data are secured in some manner. Using Passport OIDCStrategy for the protected routes will look something like:
app.all('/app/*', function(req, res, next) {
//Check that the user has previously been authenticated
if (req.user){
next();
} else {
// require the user to log in
res.redirect("/login");
}
});
I dont think you can... Nodejs is serverside... so anything you put under Nodejs, will go to the server...
If the USER click on some button or some other event triggers a process that generates the CSV file, then the USER will have to choose where they want to save it or the file will be downloaded automatically to the default Downloads directory that was specified under USER's browser settings...
I want to store some user values, name and email, in a Postgres DB on an app hosted by Heroku. This is the code in my controller;
var pg = require('pg');
...
$scope.addUser = function() {
pg.connect(process.env.DATABASE_URL, function(err, client) {
var query = client.query('INSERT INTO users (name, email) VALUES (\'' + $scope.user.name + '\', \'' + $scope.user.email + '\')');
query.on('row', function(row) {
console.log(JSON.stringify(row));
});
});
};
I get an error saying that require is not defined, which I know is because it is not supported client side. I tried using browserify on the controller file, then updating the <script> tag in the index.html that sources the file. This leads to another error.
Removing the var pg = require('pg'); gives a "ReferenceError: pg is not defined". I just want to connect to the Postgres DB from my app and insert some values. Am I on the right track or should I be going about this differently?
See Can I use PostgreSQL (pg) in the client-side (express/node.js) as to why you can't let clients connect directly to your database. You either want to write a (lightweight) server app (probably using Node.js), or you should consider a backend-as-a-service (BaaS) like Firebase or IrisCouch so that you don't need to develop the backend at all.