In my Node application, I'm running a script to generate a DB that uses the KnexJs query builder and the PostgreSQL
"node": "~14.17.6"
"knex": "^0.95.15"
"pg": "^8.7.1"
The error I'm getting
Cannot read property 'destroy' of undefined
TypeError: Cannot read property 'destroy' of undefined
at process.value (/app/node_modules/knex/lib/knex-builder/make-knex.js:91:26)
at process.emit (events.js:315:20)
at process.exit (internal/process/per_thread.js:169:15)
at success (/app/node_modules/knex/bin/utils/cli-config-utils.js:76:11)
at Command.<anonymous> (/app/node_modules/knex/bin/cli.js:236:9)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
The script I'm running is as follow
const conn = {
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_USER,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
port: process.env.POSTGRES_PORT,
charset: 'utf8',
};
const databaseName = process.env.POSTGRES_DB;
const knex = require('knex')({ client: 'pg', connection: conn });
knex
.raw('CREATE DATABASE ??', databaseName)
.then(() => console.info('Successfully created db: ' + databaseName))
.catch((err) =>
console.warn('Warning: Unable to create db. Probably already exists.', err)
)
.finally(() => knex.destroy())
.then(() => {
const connection2 = knex({
client: 'pg',
connection: { ...conn, database: databaseName },
});
return connection2
.raw('CREATE EXTENSION IF NOT EXISTS citext')
.then(() => console.info('Successfully created extension citext'))
.catch((err) => console.error('Unable to create extension citext.', err))
.finally(() => connection2.destroy());
})
.then(() => process.exit(0));
I'm unable to understand what causes the issue and why
I think the issue probably is due to misunderstanding about what is the knex instance and what is the connection instance.
In this part:
const knex = require('knex')({ client: 'pg', connection: conn });
You defined a connection using the knex module. So, when you invoke "knex" to create a second connection below:
.then(() => {
const connection2 = knex({
client: 'pg',
connection: { ...conn, database: databaseName },
});
connection2 is not a connection because knex in this context is the desired connection. You could use the previously knex connection object.
To avoid these issues, I recommend you to separate things and rename variables to make it more explainable:
const knex = require('knex') // this is the knex module
const connection = knex({ client: 'pg', connection: conn }) // This is a connection using knex
// So you should use `connection` instead `knex`, as you are using the connection instance to perform queries
connection
.raw('CREATE DATABASE ??', databaseName)
// ...
.then(() => {
// Now this should work and return a connection
const connection2 = knex({
client: 'pg',
connection: { ...conn, database: databaseName },
});
// But as connection2 is actually the same of connection, it could be
// const connection2 = connection;
return connection2 // or return connection
.raw('CREATE EXTENSION IF NOT EXISTS citext')
.then(() => console.info('Successfully created extension citext'))
.catch((err) => console.error('Unable to create extension citext.', err))
.finally(() => connection2.destroy());
})
Another point to talk about is that if is really necessary to ends the connection and to create another one just after first destroy() call. As you can have an instance to the connection, so you can use it while you are performing queries and just destroy it once if it is not necessary anymore.
Related
I'm trying to use postgres (pg) inside electron.
When the window opens, the connection and query works normally, but when the electron window is reloaded, pg connect and queries does not return anything.
<script>
const { Client } = require('pg')
async function query() {
const client = new Client({
host: '192.168.99.100',
port: 5433,
user: 'user',
password: 'password',
database: 'database',
})
console.log(await client.connect())
const res = await client.query('SELECT * from users')
console.log(res)
await client.end()
}
query()
</script>
PS: If i try to use Knex for connect and query the database, it returns this error:
Uncaught (in promise) KnexTimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
at Client_PG.acquireConnection
[nodemon] starting node server.js
C:\Users\Abhay\Desktop\todo-app\node_modules\mongodb\lib\utils.js:725
throw error;
^
TypeError: Cannot read property 'db' of undefined
at C:\Users\Abhay\Desktop\todo-app\server.js:8:17
at C:\Users\Abhay\Desktop\todo-app\node_modules\mongodb\lib\utils.js:722:9
at C:\Users\Abhay\Desktop\todo-app\node_modules\mongodb\lib\mongo_client.js:223:23
at C:\Users\Abhay\Desktop\todo-app\node_modules\mongodb\lib\operations\connect.js:279:21
at QueryReqWrap.callback (C:\Users\Abhay\Desktop\todo-app\node_modules\mongodb\lib\core\uri_parser.js:56:21)
at QueryReqWrap.onresolve [as oncomplete] (dns.js:202:10)
[nodemon] app crashed - waiting for file changes before starting...
let express = require('express')
let mongodb = require('mongodb')
let app = express()
let db
let connectionString = 'mongodb+srv://todoAppUser:kTL7PYesKzfB6FMz#cluster0.fif5n.mongodb.net/TodoApp?retryWrites=true&w=majority'
mongodb.connect(connectionString, {useNewUrlParser: true, useUnifiedTopology: true}, function(err, client) {
db = client.db()
app.listen(3000)
})
It seems you're trying to use the static connect method of MongoClient to make a connection to your db, but you are not using the MongoClient class itself.
To connect to any db, you will need a connected instance of MongoClient. Using the static connect method, you can achieve it in the following way:
const mongodb = require("mongodb");
const connectionURL = "mongodb+srv://your-connection-srv-here"
const dbName = "your_db_name"
//get MongoClient
const MongoClient = mongodb.MongoClient;
let db = null;
MongoClient.connect(connectionURL,{
useNewUrlParser: true,
useUnifiedTopology: true
},(err,connectedClient) => {
if(err){
throw err;
}
//connectedClient will be the connected instance of MongoClient
db = connectedClient.db(dbName);
//now you can write queries
db.collection("your_collection").find({}).toArray()
.then(r => {
console.log(r);
}).catch(e => {
console.error(`ERROR:`,e);
})
})
However, using callbacks will be quite cumbersome. As per the docs linked above, most functions in the MongoDb driver for Node.js will return a promise if a callback function is not passed, which is very convenient. Using this, you can write a function which return a promise that resolves a connected instance to your db.
const MongoClient = require('mongodb').MongoClient;
/*
we draw the connection srv and the db name from the config to return just one instance of that db.
Now this function call be called wherever a connection is needed
*/
const getDbInstance = (config) => new Promise((resolve,reject) => {
const client = new MongoClient(config.dbUrl, {
useNewUrlParser: true,
useUnifiedTopology: true
});
client.connect((error) => {
if(error){
console.error(error);
reject(error);
}
let db = client.db(config.dbName);
resolve(db);
})
})
const doSomeDbOperations = async() => {
//hardcoding it here, but this config will probably come from environment variables in your project
const config = {
dbUrl: "mongodb+srv://your-connection-srv-here",
dbName: "your_db_name"
};
try{
const db = await getDbInstance(config);
//do whatever querying you wish here
}catch(e){
console.error(`ERROR: `,e);
}
}
doSomeDbOperations();
This question already has answers here:
db.collection is not a function when using MongoClient v3.0
(13 answers)
Closed 3 years ago.
I'm setting up a new app using an Atlas Database with node and all i get is an error saying " MongoError: MongoClient must be connected before calling MongoClient.prototype.db".
const uri = "mongodb+srv://alberto:pass#lel-kicis.mongodb.net/test";
const client = new MongoClient(uri, { useNewUrlParser: true });
client.connect(err => {
const collection = client.db("test").collection("students")
.then(db => console.log('DB conectada'))
.catch(err => console.log(error));
});
If you look at the mongodb connector docs, the syntax for MongoClient is new MongoClient(url, options, callback). The signature for the callback is (err, client) => { //body }.
If you don't pass in the optional callback, you get and instance of MongoClient (which is the case here). The connect method also expects the same callback signature, so your connection should be like:
const instance = new MongoClient(uri, { useNewUrlParser: true });
// notice 'client' in the callback
instance.connect((err, client) => {
if (err) console.log('failed to connect')
else {
console.log('connected')
const collection = client.db("test").collection("students")
...
}
});
mongodb connector also support promise, so you can also do:
// connection is a promise
const connection = instance.connect()
connection.then((err, client) => { // etc })
Using mongoose and mongodb-uri :
Here is the way I initialise the connection :
const mongoose = require('mongoose')
const uriUtil = require('mongodb-uri')
// Create a new connection
mongoose.Promise = global.Promise
// mongoose.set('debug', DEBUG)
const dbURI = uriUtil.formatMongoose(process.env.MONGO_URI)
const options = {
autoIndex: DEBUG,
autoReconnect: true,
useNewUrlParser: true
}
const conn = mongoose.createConnection(dbURI, options)
conn.on('open', () => console.log('DB connection open'))
conn.on('error', err => console.log(`DB connection error : ${err.message}`, err))
conn.on('close', () => console.log('DB connection closed'))
module.exports = conn
Using the connection string provided by mongoDb for driver node.js version 3.0 or later.
You are missing to initiate the mongo client.
const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://alberto:pass#lel-kicis.mongodb.net/test";
const client = new MongoClient(uri, { useNewUrlParser: true });
client.connect(err => {
const collection = client.db("test").collection("students")
.then(db => console.log('DB conectada'))
.catch(err => console.log(error));
});
Also, Atlas generate the initial connection code block for you. Follow the below steps.
Clck on connect button
Select Connect Your Application from the next window
On the next window, Select NodeJs as driver and select the required version. Also, select Full driver example for full code block
Now copy the code and use it directly.
const sql = require("mssql");
var sqlconfig = {
server:"192.168.200.5",
database:"DATA",
user: "labo",
password: "*********",
connectionTimeout: 30000,
port: 1433,
dialect: "mssql",
dialectOptions: {
"instanceName": "SQLEXPRESS"
},
};
new sql.ConnectionPool(sqlconfig).connect().then(pool => {
console.log(pool); return pool.query('select * from data where id = 2')
}).then(result=> {
console.dir(result)
}).catch(err => {
console.log(err);
})
Problem: Return Login failed for user 'Labo' ELOGIN when trying to login to Microsoft SQL Server using node.js.
What I have tried: Grab the example codes on npm to find the avoid extra problems. Error still persisted.
What I suspect: The username I inserted was "labo" but the one returned from err was 'Labo' (with capitalized 'L'). Is this a bug?
This is my code
I tried to connect the DB via MySQL Java Script as below:
var mysql = require('mysql');
var con = mysql.createConnection({
host: "******",
user: "******",
password: "******"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
});
And I'm using Node to execute, While I execute the above program getting the below error message:
if (err) throw err;
^
Error: connect ECONNREFUSED XX.XXX.XX.XXX:3306
at Object.exports._errnoException (util.js:1018:11)
at exports._exceptionWithHostPort (util.js:1041:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1086:14)
Also I have pinged my ip address (ping XX.XXX.XX.XXX) and can able to get the response. Can help me to connect the DB.
I had the same issue and the error resolved by adding the socketPath parameter
var connection = mysql.createConnection({
user: 'user',
password: 'pass',
socketPath: '/var/run/mysqld/mysqld.sock',
database: 'dbname'
});
I highly suggest creating a connectionPool to save your resources. Here is how I did it:
//import settings.js
const db_config = {
hostname : "localhost",
user : settings.user, //username
password : settings.password, //password
database : settings.database //db
}
//create db connection pool
const con = mysql.createPool(db_config);
So the next step is to use that connection pool! Don't be scared about the async/bluebird nature of this code, it's just how I built it.
async function query(sql, params) {
const connection = await con.getConnectionAsync();
return connection.queryAsync(sql,params)
.then(rows => rows)
.finally(() => connection.release());
}
This is grabbing the connection getConnection method (Async is from bluebird promisifying the method), and using the query method (async'd), and then finally releasing the connection back into the pool. This helps save you from memory leaks caused by unclosed TCP connections.
Make sure that you also specify the port if you have changed it from the default MySQL port as well.