I'm using sequelize with sqlite3 inside nodejs.
The connection to database file runs fine with no error, but when trying to access it for the first time I'm getting the following error (no matter what table or query I try to do):
TypeError: Cannot read property 'findOne' of undefined
at l.a.sequelize.authenticate.then (/usr/local/bin/aeirtu/node/webpack:/server.js:55:1)
at tryCatcher (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/promise.js:693:18)
at Async._drainQueue (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/async.js:133:16)
at Async._drainQueues (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/async.js:143:10)
at Immediate.Async.drainQueues [as _onImmediate] (/usr/local/bin/aeirtu/node/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:763:18)
at tryOnImmediate (timers.js:734:5)
at processImmediate (timers.js:716:5)
Here is my connection code:
My node.js code:
import express from "express";
import models from "./models";
const app = express();
models.sequelize
.authenticate()
.then(() => {
console.log("Connected to repository");
})
.catch(err => {
console.log("ERROR connecting to repository.");
console.log(err);
});
let port = 3001;
app.listen(port, () => {
console.log("Server listening on port " + port);
});
My models.js:
import Sequelize from "sequelize";
import fs from "fs";
import path from "path";
const DATABASE_FILENAME = "test.db";
const fileWithPath = path.join(process.env.TEST_HOME, 'data', DATABASE_FILENAME);
let basename = path.basename(__filename);
let env = process.env.NODE_ENV || "development";
let db = {};
console.log("Connecting to repository at " + fileWithPath);
// database wide options
let opts = {
dialect: "sqlite",
storage: fileWithPath,
define: {
//prevent sequelize from pluralizing table names
freezeTableName: true,
// don't add the timestamp attributes (updatedAt, createdAt)
timestamps: false
},
operatorsAliases: Sequelize.Op, // use Sequelize.Op https://github.com/sequelize/sequelize/issues/8417#issuecomment-334056048
};
let sequelize = new Sequelize(DATABASE_FILENAME, null, null, opts);
fs
.readdirSync(__dirname)
.filter(file => {
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
);
})
.forEach(file => {
let model = sequelize["import"](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
export default db;
And a simple test code:
import db from "./models";
db.TestTable.findOne().then(data => {
if (!data) console.log("ERROR FETCHING DATA");
console.log(data.name);
});
I've triple checked: the sqlite3 file is in the correct location and the tables are there with data. For some reason I'm not being able to access then. I've also changed chmod a+rwx at the database file.
you forgot to import the *TestTable model`
db.TestTable = require('./TestTable')(sequelize, Sequelize);
your model.js should be a connection
but there are no define model yet like
module.exports = (sequelize, DataTypes) => {
const testTable = sequelize.define('model', {
states: {
type: Sequelize.ENUM,
values: ['active', 'pending', 'deleted']
}
});
return testTable;
};
Sample
Related
I was working with a NodeJS project and I got an error after declaring a class.
const { MongoClient } = require("mongodb");
const { EventEmitter } = require("events");
class DbConnection extends EventEmitter{
mongoClient = new MongoClient(
"mongodb+srv://xxxx:xxxx#xxxx.xxxx.mongodb.net/xxxx?retryWrites=true&w=majority",
{ useNewUrlParser: true, useUnifiedTopology: true }
);
getConnection(){
this.mongoClient.connect((err, mongodb) => {
console.log(mongoClient);
if (err) throw err;
this.emit("dbConnection", {
db: this.mongoClient.db("passport")
});
DbConnection.setInstance(mongodb);
});
}
static setInstance(mongodb){
DbConnection.db = mongodb.db("passport");
DbConnection.userCollection = DbConnection.db.collection("user");
}
}
module.exports = DbConnection;
The error is at line 6 of this file (mongoClient = new MongoClient). The error is:
mongoClient = new MongoClient(
^
SyntaxError: Unexpected token =
I don't understand the reason considering that in another project I used the same code and it works.
Any solution? Tnx
Use mongoose instead
const mongoose = require('mongoose');
module.exports = () => new Promise((resolve, reject) => {
const { dbhost, dbuser, dbpass, dbname, dbport } = process.env;
let connection_url = `mongodb://${dbuser}:${encodeURIComponent(dbpass)}#${dbhost}:${dbport}/${dbname}`
mongoose
.connect(connection_url, { useNewUrlParser: true, useUnifiedTopology: true
})
.then(async () => {
winston.info(`Connected to ${connection_url} ...`);
mongoose.set('debug', true);
resolve();
}).catch(reject);
})
It is worked for me.
I'm trying to set up an apollo server and an error shows up.
import { createConnection } from "typeorm";
import { Post } from "./entity/Post";
const express = require("express");
import { buildSchema } from "type-graphql";
import { ApolloServer } from "apollo-server-express";
import { PostResolver } from "./Resolvers/post";
createConnection()
.then(async (connection) => {
console.log("Inserting a new user into the database...");
const post = new Post();
post.firstName = "Timber";
post.lastName = "Saw";
post.age = 25;
await connection.manager.save(post);
console.log("Saved a new user with id: " + post.id);
console.log("Loading users from the database...");
const posts = await connection.manager.find(Post);
console.log("Loaded users: ", posts);
const app = express();
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`Listening on PORT: ${PORT}`));
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [PostResolver],
}),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
})
.catch((error) => console.log(error));
[ERROR] 16:49:21 тип Unable to compile TypeScript:
src/index.ts:27:43 - error TS2345: Argument of type '{ schema: GraphQLSchema; }' is not assignable to parameter of type 'Config'.
Type '{ schema: GraphQLSchema; }' is missing the following properties from type 'Config': formatError, debug, rootValue, validationRules, and 6 more.
I've tried installing dependencies again, changed TypeScript config, restarting the whole project but nothing seems to fix the problem. Any clue?
Whenever I try to run the function refreshStock() in an endpoint in one of the API endpoints /api/seller/deactivate it gives me this error:
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1318:16)
at listenInCluster (net.js:1366:12)
at Server.listen (net.js:1452:7)
at C:\Users\***\Documents\GitHub\***\***\.next\server\pages\api\seller\deactivate.js:191:10
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command
It looks like it's trying to restart the server, but it happens after it compiles, is there something I'm doing wrong, I've followed a couple of tutorials on medium, and they give this same type of code, just not ES Modules. I want to use ES Modules because it is what my database functions are written in.
Server.js:
import express from 'express';
import { createServer } from 'http';
import next from 'next';
import models from './server/models';
import { genStock } from './server/lib/functions';
import { Server } from 'socket.io';
const port = parseInt(process.env.PORT || '3000', 10);
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
const app = express();
const server = createServer(app);
const io = new Server(server);
const Users = models.users;
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
if (!socket.handshake.auth.token) return next(err);
let user = await Users.findOne({
where: {
socket_token: socket.handshake.auth.token,
},
});
if (!user) {
console.log('unauthenticated socket');
socket.disconnect();
next(err);
}
await Users.update(
{ socket_id: socket.id },
{
where: {
socket_token: socket.handshake.auth.token,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
// Works fine
const stock = await genStock();
socket.emit('updateStock', stock);
});
// Fails with address already in use :::3000
export async function refreshStock() {
const stock = await genStock();
io.emit('updateStock', stock);
}
nextApp.prepare().then(async () => {
app.all('*', (req, res) => nextHandler(req, res));
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
This is meant to refresh the stock after a seller deactivates their account and sends all users the new stock.
/api/seller/deactivate
....
await refreshStock();
....
I figured it out, I just split up the WebSocket server and the next.js one. I have whitelisted local IPs that may appear to only allow server-to-server communication. Although I don't think this is full-proof as there is most likely a better way to have this type of communication but for now it works.
/**
* This server cannot be imported in /api folders, it won't work.
* Although it can import other functions
* */
import express from 'express';
import { createServer } from 'http';
import session from 'express-session';
import { Server } from 'socket.io';
import { genStock } from './server/lib/stockFunctions';
import { sessionStore } from './server/lib/session';
import passport from './server/lib/passport';
import models from './server/models';
const authorizedIPs = ['::1', '127.0.0.1', '::ffff:127.0.0.1'];
const Users = models.users;
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: `http://localhost:3000`,
methods: ['GET', 'POST'],
credentials: true,
},
});
const wrap = (middleware) => (socket, next) => middleware(socket.request, {}, next);
io.use(
wrap(
session({
secret: "---",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/',
sameSite: 'lax',
},
store: sessionStore,
}),
),
);
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use(async (socket, next) => {
const err = new Error('Unauthorized');
err.data = { message: 'Unauthorized, please try again later.' };
try {
const user = socket.request.user;
if (!user) return next(err);
await Users.update(
{ socket_id: socket.id },
{
where: {
id: user.id,
},
},
);
next();
} catch (e) {
console.log(e);
next(e);
}
});
io.on('connection', async (socket) => {
const stock = await genStock();
socket.emit('updateStock', stock);
});
app.post('/refresh-stock', async function (req, res) {
const ip = req.ip;
if (!authorizedIPs.includes(ip)) {
console.log(ip);
return res.status(401).json({ success: false });
}
const newStock = await genStock();
io.emit('updateStock', newStock);
return res.status(200).json({ success: true });
});
httpServer.listen(3001);
console.log(`> Websockets ready on http://localhost:3001`);
I have an issue with the Authenticati onController used with sequelize and sqlite
When I test the POST request using postman, it always gives status 400 with the response
{
error: 'Something is wrong'
}
This is the log
::1 - - [21/Jul/2020:15:40:33 +0000] "POST /register HTTP/1.1" 400 30 "-" "PostmanRuntime/7.26.1"
Here is the code of AuthenticationController
const {User} = require('../models')
module.exports = {
async register(req, res){
try {
const user = await User.create(req.body)
res.send(user.toJSON())
} catch (error) {
console.log(error)
res.status(400).send({
error: 'Something is wrong'
})
}
}
}
User model code
module.exports = (sequelize, DataTypes) =>
sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
})
models index code
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
)
fs
.readdirSync(__dirname)
.filter((file)=>{
file != 'index.js'
})
.forEach((file)=>{
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
// const model = sequelize.import(path.join(__dirname,file))
db[model.name] = model
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
routes code
const AuthenticationController = require('./controllers/AuthenticationController');
module.exports = (app) => {
app.post('/register',
AuthenticationController.register)
}
Earlier, it was throwing an error of "TypeError: Cannot read property 'create' of undefined"
But when I restarted the server, that was fixed. But I have no clues as to why the try block fails.
Anyone could throw some light on this? Thank you
Here is the revised code for /models/index.js
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
)
fs.readdirSync(__dirname)
// .filter((file) => {
// file != "index.js";
// })
.filter(
(file) =>
file.indexOf(".") !== 0 && file !== "index.js" && file.slice(-3) === ".js"
)
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
// const model = sequelize.import(path.join(__dirname,file))
db[model.name] = model;
});
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
The filter block was updated as shown in the revised, with the help of the link
https://www.codota.com/code/javascript/functions/sequelize/Sequelize/import
The 2 things that were changed are
Replaced the 'sequelize.import' with 'require'
Updated the 'filter' block as shown.
Here is the result:
Thanks to crumkev for the insight which led me find the answer.
[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();