node/pg/PSQL: Create Tables using Promises - javascript

I am writing a simple Node/Express/React/Postgres application and I'm using the pg package to interface with my Postgres Server.
I require three tables, table1, table2, and table3. table2 has a foreign key in table1 and table3 has a foreign key in table 2, so the order that I need to create the tables in is: table1 then table2 then table3.
I am attempting to use promises to enforce this order in my asynchronous table creation calls. I've generally followed Brian Carlson's suggested Project Structure, but clearly I'm doing something wrong.
Here are the simplified, relevant files from my project:
db.js:
const { Pool } = require('pg');
// Create pool connection to database
const pool = new Pool({
user: XXXX,
host: XXXX,
database: XXXX,
password: XXXX,
port: XXXX
});
// Pool emitters
pool.on('connect', () => {
console.log('Connected a client to the database');
});
pool.on('remove', () => {
console.log('Disconnected a client from the database');
});
pool.on('error', (err, client) => {
console.error('Unexpected error on idle client', err);
process.exit(-1);
});
// This structure taken from Brian Carlson's pg API Documentation
// https://node-postgres.com/guides/project-structure
module.exports = {
query: (text, params) => {
console.log('Making a query!');
return pool.query(text, params);
}
};
table_scripts.js:
const db = require('../db');
const Database_Scripts = {
create_table_1: () => {
const create_table_1_query = {
text: `CREATE TABLE IF NOT EXISTS
public.table_1
(
id smallserial,
name text NOT NULL,
PRIMARY KEY (id)
);`
};
return db.query(create_table_1_query);
},
create_table_2: () => {
const create_table_2_query = {
text: `CREATE TABLE IF NOT EXISTS
public.table_2
(
id smallserial,
table_1_id integer NOT NULL REFERENCES public.table_1(id),
name text NOT NULL,
PRIMARY KEY (id)
);`
};
return db.query(create_table_2_query);
},
create_projects_table: () => {
const create_table_3_query = {
text: `
CREATE TABLE IF NOT EXISTS
public.table_3
(
id smallserial,
table_3_id integer NOT NULL REFERENCES public.table_2(id),
name text NOT NULL,
PRIMARY KEY (id)
);`
};
return db.query(create_table_3_query);
}
};
module.exports = Database_Scripts;
create_tables.js:
const Table_Scripts = require('./table_scripts');
Table_Scripts.create_table_1()
.then(Table_Scripts.create_table_2())
.then(Table_Scripts.create_table_3())
.catch(error => console.log(error.stack));
package.json:
{
"name": "app",
"version": "0.0.0",
"scripts": {
"start": "nodemon ./bin/www",
"create_tables": "node ./database/scripts/create_tables.js"
}
}
When I run my create_tables script (npm run-script create_tables), I get the following (sanitized) errors:
Connected a client to the database
Connected a client to the database
Connected a client to the database
Disconnected a client from the database
(node:13444) UnhandledPromiseRejectionWarning: error: relation "public.table_1" does not exist
(node:13444) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a
catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:13444) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Disconnected a client from the database
(node:13444) UnhandledPromiseRejectionWarning: error: relation "public.table_2" does not exist
(node:13444) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a
catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
Disconnected a client from the database
I've been able to get this script to work converting the functions to async functions, however, I'd really like to understand what I'm doing wrong here.

Your problem seems to be that you're concurrently creating the tables despite explicitly needing to do the opposite.
According to the documentation, pool.query() returns a promise if not provided a callback function as a third argument. You need to wait for each of your db.query() promises to be resolved. Thus it'll wait for the first table to be created, then create the second one and finally the third one.
I would recommend using the async/await syntax
async function createTables () {
try {
const create_table_1_query = {
text: `yourQuery1`
};
// awaits for the first table to be created
await db.query(create_table_1_query);
const create_table_2_query = {
text: `yourQuery2`
};
// awaits for the second table to be created
await db.query(create_table_2_query);
const create_table_3_query = {
text: `yourQuery3`
};
// awaits for the third table to be created
await db.query(create_table_3_query);
} catch (e) {
console.error(e.stack);
}
}
module.exports.createTables = createTables;
You can then call await createTables();

Related

field in mongoose model is required : true but it is being created in postman

i am trying to give only name in the body and want error in the postman ...but for the status response in postman is 201 created but it is throwing error in console as
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: password: Path password is required., email: Path email is required.
at model.Document.invalidate (C:\projects\MERN\backend\node_modules\mongoose\lib\document.js:2564:32)
at C:\projects\MERN\backend\node_modules\mongoose\lib\document.js:2386:17
at C:\projects\MERN\backend\node_modules\mongoose\lib\schematype.js:1181:9
at processTicksAndRejections (internal/process/task_queues.js:79:11)
(node:6524) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:6524) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
why there is no error in postman???????????
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
name:{
type : String,
required : true
},
email:{
type : String,
required : true,
unique:true,
},
password:{
type : String,
required : true,
minlength: 7
},
date:{
type :Date,
default: Date.now
}
})
const User = mongoose.model('User',userSchema)
module.exports = User
router.post("/", async (req, res) => {
try {
const user = await new User(req.body);
user.save();
res.status(201).send({user});
} catch (e) {
res.status(500).send(e);
}
});
consider that your node application throws some error right and crashes as you describe well above. Because your node app is interfacing with the internet you need to devise a way to interpret the error from you app into to an error that is known by the internet also, that way postman will be able to tell that an error has occured...So how do we achieve this, the answer is error handling...
We will use your User model as you have described, and consider the code below it...
router.post("/", async (req, res) => {
try {
const user = await new User(req.body);
// One important thing to note is that the return of this function call below is
// a Promise object which means that it executes asynchrounously and from the error
// log you have above, it is the reason your app is crashing...
user.save();
res.status(201).send({user});
} catch (e) {
res.status(500).send(e);
}
});
So then lets fix it...
router.post("/", async (req, res) => {
const user = await new User(req.body);
return user.save()
// the then call simply accepts a callback that is executed after the async is complete
.then((result) => res.status(201).send({user}))
// this catch will be called in case the call encounters an error during execution
.catch((error) => res.status(500).send(error));
});
Note now we handle the error in the catch by responding to the HTTP request as you have with a 500 code...and also sending the error along with the response

Node UnhandledPromiseRejectionWarning when saving to MongoDb

New to node- I'm trying to save some of my tweets from Twitter API into mongo using Twit package.
I've connected to mongodb on port 27017 using mongoose, and this piece of code I've written seems to save the tweets to my db, however I seem to be getting this warning back everytime I save a document:
(node:9991) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 8)
Here is my code:
const Tweet = require('./app/models/tweet.model.js');
const dbConfig = require('./config/database.config.js');
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect(dbConfig.url, {
useNewUrlParser: true
}).then(() => {
console.log("Successfully connected to the database");
}).catch(err => {
console.log('Could not connect to the database. Exiting now...', err);
process.exit();
});
var Twit = require("twit");
var config = require("./config/twitter.config");
var T = new Twit(config);
var params = {
screen_name: "decade3uk",
count: 2
};
T.get("statuses/user_timeline", params, gotData);
function gotData(err, data, response) {
var tweets = data;
for(var i=0;i<tweets.length;i++){
const tweet = new Tweet({
created_at:tweets[i].created_at,
id_str:tweets[i].id_str,
text:tweets[i].text
});
tweet.save()
.then(entry => {
response.send(entry);
}).catch(err => {
response.status(500).send({
message: err.message || "Some error occurred while creating the Tweet."
});
});
}
}
What is best practice to get rid of this error?
Why don't you try to find where is that exception coming from and what exactly it is. You can find that by adding the following code to your server file, just to make sure you get what's causing the exception.
process.on('unhandledRejection', (reason, promise) => {
console.log("Reason: ",reason,"promise: ",promise);
})

asynchronous issues adding to a map in mongoose

I am trying to add my googleID (object) to a map in another mongoose schema. I stringify my user id object, and during my test code I get thrown this error:
(node:293528) UnhandledPromiseRejectionWarning: ValidationError: collection validation failed: likes.5dbf6205bdcd5e5f78536447: Cast to ObjectId failed for value "110840542851551561690" at path "likes.$*"
at new ValidationError (C:\files\node_modules\mongoose\lib\error\validation.js:30:11)
at model.Document.invalidate (C:\files\node_modules\mongoose\lib\document.js:2333:32)
at Map.set (C:\files\node_modules\mongoose\lib\types\map.js:71:26)
at C:\files\app.js:123:30
at C:\files\node_modules\mongoose\lib\model.js:4589:16
at C:\files\node_modules\mongoose\lib\query.js:4323:12
at process.nextTick (C:\files\node_modules\mongoose\lib\query.js:2805:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
(node:293528) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:293528) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
My Post request from client.js:
const likesForm = document.getElementById("test");
likesForm.addEventListener("submit", function (evt) {
evt.preventDefault();
console.log(event.target.id)
const [likeString, itemId] = evt.target.id.split("-");
vote(
likeString === "like"
? "1"
: "-1",
itemId
);
}, false);
async function vote (voteInc, itemId) {
const route = `/like/${itemId}`;
const response = await fetch(route, {
method: 'POST',
body: JSON.stringify({"like": voteInc}),
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
console.log(result);
}
Server-side post:
app.post("/like/:id",(req,res)=>{
const id = req.params.id;
const like = req.body.like;
console.log(like);
console.log(id);
if(req.isAuthenticated()){
linkscr.user.findById(req.user.id, (e,foundUser)=>{
if(e){
console.log(e);
}else{
//if like = 1
if(like==1){
linkscr.collection.findById(id, function(error,result){
if(error){
console.log(error);
}else{
result.likes.set(foundUser._id.toString(),foundUser.googleId);
result.save();
}
})
console.log("not voted yet. Add 1 and added to like");
}else{
linkscr.collection.findById(id, function(error,result){
if(error){
console.log(error);
}else{
result.dislikes.set(foundUser._id.toString(),foundUser.googleId);
result.save();
}
})
console.log("not voted yet. Add 1 and added to dislike");
};
};
});
}else{
res.redirect("/");
}
});
My likes/dislikes schema:
likes : {
type: Map,
of: {
type: mongoose.Schema.Types.ObjectId,
ref: "User" }
},
dislikes : {
type: Map,
of: {
type: mongoose.Schema.Types.ObjectId,
ref: "User" }
},
How the Schema is initially saved:
likes : {[User._id]:User},
dislikes : {},
Thanks for any and all help. You're my only hope Stack!
I first thought this was a mongoose issue with how i was treat my objects but it looks like this is more to do with the async stuff. Admittedly that's my biggest weakness in programming at the time writing this.
EDIT: From what I'm looking at from documentation mongoose can't set objects only strings. Mongo can not mongoose.
Edit 2: My bad I put in the wrong Id in the wrong place. foundUser._id.toString() ,foundUser
In order to create maps in mongoose, the key **Must be in the form of a string. Additionally Your schema (which wasn't initially shared) wanted the object_id not the google passportID. For the sake of helping out future generations I will provide an edit in the original post. Simplifying with foundUser will work in this case.
result.likes.set(foundUser._id.toString(), foundUser);

Promise and Resolve not working

const { GraphQLServer } = require('graphql-yoga');
const mongoose = require('mongoose');
mongoose.connect("mongodb://localhost/test1");
const Todo = mongoose.model('Todo',{
text: String,
complete: Boolean
});
const typeDefs = `
type Query {
hello(name: String): String!
}
type Todo{
id: ID!
text: String!
complete: Boolean!
}
type Mutation{
createTodo(text:String!): Todo
}
`
const resolvers = {
Query: {
hello: (_, { name }) => `Hello ${name || 'World'}`,
},
Mutation:{
createTodo: async (_,{ text }) => {
const todo = new Todo({text, complete: false});
await todo.save();
return todo;
}
}
};
const server = new GraphQLServer({ typeDefs, resolvers })
mongoose.connection.once("open", function() {
server.start(() => console.log('Server is running on localhost:4000'))
});
Hello I'm new to node js and mongoDB. I'm trying to start my server but it's not starting. Every time it shows a error like this:
(node:17896) UnhandledPromiseRejectionWarning: Unhandled promise rejection.
This error originated either by throwing
inside of an async function without a catch block, or by rejecting a promise
which was not handled with .catch(). (rejection id: 1)
(node:17896) [DEP0018] DeprecationWarning: Unhandled promise rejections are
deprecated. In the future, promise rejections that are not handled will
terminate the Node.js process with a non-zero exit code.
Every time this is showing some promise error.Can anyone please help me to debug this program. I m a beginner. I don't know much of it. But as per my understanding, I have written correct code only.
Probably your save function throws an arrow which you don't handle it!
you can solve this issue with one of these ways:
GraphQL handles promise by itself, so this would give you same result:
createTodo: (_,{ text }) => {
const todo = new Todo({text, complete: false});
return todo.save();
}
using try catch would give you better error handling:
createTodo: async (_,{ text }) => {
const todo = new Todo({text, complete: false});
try {
await todo.save();
return todo;
} catch(err) {
\\ do something with error
console.error('error=>', err);
return null;
}
}

Trouble understanding my errors when trying to create my MongoDB database connection on my javascript server using node.js

I am currently taking a web course and am almost always struggling to debug my code and the errors Node returns don't seem to help.
I am creating a web server and trying to create username and password authentication with MongoDB and JavaScript. When I call my initialize function I get a wack load of errors. I know it is coming from my Database initialization function because when I take it out of my initial server initialization I get no errors. For the most part this code comes from my specific assignment design document so I am not looking for anything that's more efficient etc.
Working Code without MongoDB function:
data.initialize().then(function(){
app.listen(HTTP_PORT, function(){
console.log("app listening on: " + HTTP_PORT)
});
}).catch(function(err){
console.log("unable to start server: " + err);
});
Code that isn't working:
data.initialize().then(dataServiceAuth.initialize).then(function(){
app.listen(HTTP_PORT, function(){
console.log("app listening on: " + HTTP_PORT)
});
}).catch(function(err){
console.log("unable to start server: " + err);
});
DataServiceAuth.initialize:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var userSchema = new Schema({
"userName": {
unique: true,
type: String
},
"password": String,
"email": String,
"loginHistory": [{ "dateTime": Date, "userAgent": String }]
});
let User; //to be defined on new connection
module.exports.initialize = function () {
return new Promise(function (resolve, reject) {
let db = mongoose.createConnection("mongodb://<Removed username>:<removed password>#ds017193.mlab.com:17193/web322_a6");
db.on('error', (err) => {
reject(err); // reject the promise with the provided error
});
db.once('open', () => {
User = db.model("users", userSchema);
resolve();
});
});
};
and last but not least all the errors
(node:6968) UnhandledPromiseRejectionWarning: Error: Username contains an illegal unescaped character
at parseConnectionString (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\url_parser.js:280:11)
at parseHandler (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\url_parser.js:119:14)
at module.exports (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\url_parser.js:25:12)
at connect (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\mongo_client.js:874:3)
at connectOp (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\mongo_client.js:269:3)
at executeOperation (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\utils.js:419:24) at MongoClient.connect (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongodb\lib\mongo_client.js:260:10)
at Promise (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongoose\lib\connection.js:427:12)
at new Promise (<anonymous>)
at NativeConnection.Connection.openUri (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongoose\lib\connection.js:424:19)
at Mongoose.createConnection (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\node_modules\mongoose\lib\index.js:167:17)
at C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\data-service-auth.js:18:27
at new Promise (<anonymous>)
at module.exports.initialize (C:\Users\Jasper\Desktop\School\web322\WEB322-A5-solution\data-service-auth.js:17:12)
at <anonymous>
(node:6968) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside
of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:6968) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Categories