I'm building a project with Express, trying to use the Sequelize ORM to access a mySQL database.
The errors I'm getting waver between not having models defined and findAll of Orders being a function and not an object I can query.
Is there an obvious flaw in my setup? Thanks!
Order.js:The Model
'use strict';
module.exports = (sequelize, DataTypes) => {
var Order = sequelize.define('stores', {
index: DataTypes.INTEGER,
server: DataTypes.STRING,
gridName: DataTypes.STRING,
x: DataTypes.INTEGER,
y: DataTypes.INTEGER,
z: DataTypes.INTEGER,
owner: DataTypes.STRING,
item: DataTypes.STRING,
deal: DataTypes.STRING,
quantity: DataTypes.INTEGER,
price: DataTypes.INTEGER,
GPS: DataTypes.STRING
});
return Order;
};
index.js:The model aggregator
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
// const config = require(__dirname + '/..database.json')[env];
const db = {};
let sequelize;
// if (config.use_env_variable) {
// sequelize = new Sequelize(process.env[config.use_env_variable]);
// } else {
sequelize = new Sequelize('db', 'user', 'pw', {
host: 'ip',
dialect: 'mysql2'
});
// }
fs
.readdirSync(__dirname)
.filter(function(file) {
return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js';
})
.forEach(function(file) {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
marketRoutes.js:The query controller
const models = require('../models');
module.exports = (app) => {
app.get('/api/requestOrders', (req, res) => {
console.log('hitting route', models.Order);
models.Order
.findAll()
.then(function(orders) {
console.log(orders);
})
.catch(function(err) {
console.log(err);
});
});
};
I think marketRoutes.js is looking for models in the wrong place. Shouldn't you be require index.js, so you can access the models imported from the file system and stored in the db object?
(I use a models directory... but there are some advantages to using sequelize.import)
Related
I have 3 sequelize models that i have defined imported into a file called sequelize.js like so:
const { Sequelize } = require("sequelize");
const UserModel = require("./models/user");
const ItemModel = require("./models/item");
const ReservationModel = require("./models/reservation");
const config = require("./dbconfig");
const db = config.database;
const Item = ItemModel(sequelize, Sequelize);
const User = UserModel(sequelize, Sequelize);
const Reservation = ReservationModel(sequelize, Sequelize);
Reservation.hasMany(Item);
Item.belongsTo(Reservation);
Reservation.belongsTo(User);
I then try to export them:
module.exports = { Item, User, Reservation };
However, when I try to access one of them and use a model function, I get an error.
const Model = require("../../sequelize");
const passport = require("passport");
module.exports = (app) => {
app.post("/registerUser", (req, res, next) => {
passport.authenticate("register", (err, user, info) => {
if (err) {
console.log(err);
}
if (info !== undefined) {
console.log(info.message);
res.send(info.message);
} else {
req.logIn(user, (err) => {
const data = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
username: user.email,
};
Model.User.findOne({
where: {
email: data.username,
},
}).then((user) => {
user
.update({
first_name: data.first_name,
last_name: data.last_name,
email: data.email,
})
.then(() => {
console.log("user created in db");
res.status(200).send({ message: "user created" });
});
});
});
}
})(req, res, next);
});
};
results in
TypeError: User.findOne is not a function
This is not an issue when I just export one of them.
module.exports = User;
const User = require("./sequelize");
...
User.findOne(...) //works
I've tried multiple ways of exporting, but none seem to work.
e.g
module.exports = {
Item: Item,
User: User,
Reservation: Reservation,
}
and
exports.Item = Item;
exports.User = User;
exports.Reservation = Reservation;
edit: Here is my user model for reference
module.exports = (sequelize, type) => {
return sequelize.define(
"user",
{
id: {
type: type.INTEGER,
primaryKey: true,
autoIncrement: true,
},
first_name: type.STRING,
last_name: type.STRING,
credentials: type.STRING,
email: {
type: type.STRING,
allowNull: false,
},
password: {
type: type.STRING,
allowNull: false,
},
},
{
tableName: "Users",
}
);
};
Why cant I export these multiple objects?
I have the exact structure you're using by importing all sequelize models into one file then module.exporting them in an object and the only thing I see thats different is how you define your models. I might be out of date but I learned as such:
const Sequelize = require('sequelize');
const db = require('../db');
module.exports = db.define('users', {
id: {
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
unique: true
},
}, {
timestamps: true,
});
Db declaration
const Sequelize = require('sequelize');
const db = new Sequelize(
process.env.DATABASE_URL, {
logging: false
}
);
module.exports = db;
Then your central import
const User = require('./user');
const Order = require('./order');
Order.belongsTo(User)
User.hasMany(Order)
module.exports = {
User,
Order
};
Then using it
const models = require('./models');
const results = await models.User.destroy({
where: {
id: id
}
});
if(results){
return results;
}
Found what was wrong. In my passport.js file, where I defined my localStrategy, I was doing an incorrect import.
My export in sequelize.js was
modules.export = {Item, User, Reservation};
while my import in passport.js was just
const User = require("../sequelize");
when it should have been
const Model = require("../sequelize");
const User = Model.User;
looks like I had it imported correctly in my signUp route, but not in my passport config file!
code is supposed to return a a JSON object with empty tasks when requesting /tasks instead it returns a message error- TypeError: cannot read property 'findAll' of undefined. The source of errors as per the message comes from routes >tasks.js see below for screenshots or/and live code on sandbox.
Project Folder:
sandbox
some codes:
src>models >tasks.js
module.exports = (sequelize, DataType) => {
const Tasks = sequelize.define(
"Tasks",
{
id: {
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true
},
title: {
type: DataType.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
done: {
type: DataType.BOOLEAN,
allowNull: false,
defaultValue: false
}
},
{
classMethods: {
associate: models => {
Tasks.belongsTo(models.Users);
}
}
}
);
return Tasks;
};
src>routes>tasks.js
module.exports = app => {
const Tasks = app.db.models.tasks;
app.get("/tasks", (req, res) => {
Tasks.findAll({}).then(tasks => {//source of error as per error message
res.json({ tasks: tasks });
});
});
};
src >db.js
var path = require("path");
var fs = require("fs");
var Sequelize = require("sequelize");
//const config = require("./libs/config.js");
var sequelize = null;
let db = null;
module.exports = app => {
if (!db) {
const config = app.libs.config;
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config.params
);
db = {
sequelize,
Sequelize,
models: {}
};
const dir = path.join(__dirname, "models");
fs.readdirSync(dir).forEach(file => {
const modelDir = path.join(dir, file);
const model = sequelize.import(modelDir);
db.models[model.name] = model;
});
Object.keys(db.models).forEach(key => {
db.models[key].options.classMethods.associate(db.models);
});
}
return db;
};
src>index.js
var express = require("express");
var consign = require("consign");
var app = express();
consign({ cwd: "src" })
.include("./libs/config.js")
.then("db.js")
.then("./libs")
.then("./routes")
.into(app);
On file routes/tasks.js line 2, add a capital on task;
const Tasks = app.db.models.Tasks;
Then it should works.
I need to connect to different databases depending on the Express route.
For example:
example.com/oneapp
This route must access a database called oneapp
example.com/secondapp
This route must access a database called secondapp
I have these settings in my Sequelize
index.js:
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const config = require('../../config/database.js');
const db = {};
const sequelize = new Sequelize(config.producao);
fs
.readdirSync(__dirname)
.filter(file => (file.indexOf('.') !== 0) && (file !== path.basename(__filename)) && (file.slice(-3) === '.js'))
.forEach((file) => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
console.log(db)
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
database.js
module.exports = {
"producao": {
username: 'sa',
password: 'mypass',
database: 'PRODUCAO',
host: 'SVRNAZ002',
dialect: 'mssql',
}
}
Run that code twice with different db settings and keep two sets of the sequelize connection object and array of models.
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const configs = [require('../../config/database.js'), require('../../config/database2.js')];
module.exports = configs.map(config => {
const db = {};
const sequelize = new Sequelize(config.producao);
// load stuff like normal
db.sequelize = sequelize;
db.Sequelize = Sequelize;
return db;
});
Now you can access both:
const models = require('index');
const firstdb = models[0];
const seconddb = models[1];
maybe this is not the right answer, but I use it and it works.
first I use it for databases usually, the second for images
db.js
const {Sequelize} = require('sequelize')
const config = [
{
dialect: 'sqlite',
storage: './db.sqlite'
},
{
dialect: 'sqlite',
storage: './db_gambar.sqlite'
}
]
const database = config.map( x => new Sequelize(x));
module.exports = { database }
./models/akun.js
const { DataTypes, Model } = require('sequelize');
const { database} = require('./../db');
const sequelize = database[0];
// Tambahan is extend Model
class Akun extends Tambahan{}
Akun.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false,
}
},{ sequelize, underscored: true})
./models/gambar.js
const { DataTypes, Model } = require('sequelize');
const { database } = require('./../db');
const sequelize = database[1];
// Tambahan is extend Model
class Gambar extends Tambahan{}
Gambar.init({
name: {
type: DataTypes,
allowNull: false
},
user_id: {
type:DataTypes.INTEGER,
allowNull: false
},
data: {
type:DataTypes.BLOB,
allowNull: false
},
thumbnail: {
type: DataTypes.BLOB,
allowNull: false
}
},{ sequelize , underscored: true})
I am using sequelize orm in node.js. I have made models folders for all model like userModel.js, in userModel.js I have some class-based functions like login and getToken.
// some code of userModel.js
const jwt = require('jsonwebtoken');
module.exports = (sequelize, Sequelize) => {
const UserSchema = sequelize.define('User', {
first_name: {
type: Sequelize.STRING,
},
last_name: {
type: Sequelize.STRING,
},
});
// generate token
UserSchema.genToken = (id) => {
return jwt.sign({ id }, 'test');
}
// user login
UserSchema.login = function (body) {
const User = this;
return User.findOne({
where: { email: body.email}
})
.then((result) => {
return result;
})
.catch((err) => {
return Promise.reject(err);
})
}
return UserSchema;
}
when i import userModel.js in db.js
const Sequelize = require('sequelize');
const config = {};
var db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, {
host: config.host,
dialect: config.dialect,
operatorsAliases: false,
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = sequelize.import('./../models/userModel');
module.exports = db;
so my question is when I using db variable for userModel like
db.User
I am using VS code editor for coding. So now VS code is showing me all suggestion of sequelize models but it is not showing my functions for login and genToken
//suggest
db.User.find()
db.User.findOne()
//but not include these
db.User.login()
db.User.genToken()
Even when I use db.User.login() or db.User.genToken() it's working as I want but right now I will have to open userModel.js again and again for seeing the name of all functions. How can I import models in a better way?
I have the following file structure:
models/
index.js
something.js
user.js
In index.js (this is generated by Sequalize and importing stuff from here works in other directories):
'use strict';
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var basename = path.basename(module.filename);
var env = process.env.NODE_ENV || 'development';
var config = require(__dirname + '/../config/config')[env];
var db = {};
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(function(file) {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db; // <<< I want to import that in something.js
user.js:
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
username: { type: DataTypes.STRING, allowNull: false, unique: true },
password: { type: DataTypes.STRING, allowNull: false },
}, {
classMethods: {
associate() {},
},
});
return User;
};
something.js:
'use strict';
// this all logs an empty object
console.log(require('./index'));
console.log(require('.'));
console.log(require('./'));
console.log(require('../models'));
console.log(require('../models/'));
console.log(require('../models/index'));
module.exports = (sequelize, DataTypes) => {
const Something = sequelize.define('Something', {
name: DataTypes.STRING,
}, {
classMethods: {
associate(models) {
},
},
});
return Something;
};
If I require db from files in other directories it works so I guess it's not a problem with exporting.
How can I require db in something.js so it's not undefined?
const neededStuff = require('./'); // the best
or:
const neededStuff = require('./index');
or:
const neededStuff = require('../models/');
Turns out it was a circular dependency. index.js was importing stuff from something.js and then I tried to import index.js in something.js.
If module A requires('B') before it has finished setting up it's exports, and then module B requires('A'), it will get back an empty object instead what A may have intended to export.
http://selfcontained.us/2012/05/08/node-js-circular-dependencies/
But you can use methods from another model in sequelize with sequelize.models.Something.