I'm using sequelize on my ReactJS application to access my database. Follow the tutorial, below is my sequelize initializer used to load all models and make then available to db:
"use strict";
var fs = require("fs");
var path = require("path");
var Sequelize = require("sequelize");
var basename = path.basename(__filename);
var env = process.env.NODE_ENV || "development";
var config = require(__dirname + "/../config/config.js")[env];
var db = {};
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
var sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (
file.indexOf(".") !== 0 &&
file !== basename &&
file.slice(-3) === ".js"
);
})
.forEach(file => {
var 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;
module.exports = db;
This is how a simple model looks like: TestModel.js
export default (sequelize, DataTypes) => {
let TestModel = sequelize.define("TestModel", {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
name: { type: DataTypes.STRING(32), allowNull: false },
description: { type: DataTypes.STRING(256) }
});
return TestModel;
};
And then I can normally use it inside my code:
db.TestModel.find(...);
All running fine, until I need to prepare the production bundle.
I'm using webpack to prepare the production bundle that is delivered as a single file. When doing so, the model files are not any more available for importing at:
fs
.readdirSync(__dirname)
.filter(file => {
return (
file.indexOf(".") !== 0 &&
file !== basename &&
file.slice(-3) === ".js"
);
})
.forEach(file => {
var model = sequelize["import"](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
.. and then there are no more models available to be used from db, what causes my database access code db.TestModel.find(...); to fail with the following error: TypeError: Cannot read property 'find' of undefined
Naturally no files were imported (there is just my bundle.js) and db does not contain the model definition.
So, I need a way to statically import the models, and here is my try:
import TestModel from "./TestModel.js";
.
.
.
db[TestModel.name].associate(db);
Althought this runs, it does not associate and I'm getting the same error at runtime.
How can I statically associate my models to sequelize db so that I can access then directy as db.ModelName ?
Related
So I'm learning sequelize with MySQL and I have a few examples at my disposal on how it should be done, but this error persists as if sequelize couldn't use the functions inside the model. I just can't find why it's not working, any help?
This is the error that shows in the terminal, it points to productController line 8:
TypeError: Cannot read properties of undefined (reading 'findAll')
This is my Index.js:
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.js')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file));(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
This is the Table Model:
module.exports = (sequelize, DataTypes) => {
let alias = 'Product';
let atributes = {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
}
let config = {
tableName: 'products',
timestamps: false
}
const Product = sequelize.define(alias, atributes, config);
return Product
}
And This productController.js:
const db = require('../../models/Index');
const sequelize = db.sequelize;
const productsController = {
'shopRender' : (req, res) => {
// res.send('hola mundo');
db.Product.findAll()
.then(function(productos) {
res.send("hola mundo");
})
}
}
module.exports = productsController;
Ive tried deconstructing db in productController into Product, using caps, non-caps, using the table name...
What does work is trying to show something inside the shopRender function, but once I try to use the model to do a query and try to access the route, the error appears.
Turns out, trying to use res.send(Object.keys(db)) to debug prints ["undefined","","sequelize","Sequelize"]
try this on a productController.js, I hope it helps.
const db = require('../../models').sequelize.models;
const productsController = {
'shopRender' : (req, res) => {
// res.send('hola mundo');
db.Product.findAll()
.then(function(productos) {
res.send("hola mundo");
})
}
}
module.exports = productsController;
OBS. Excuse my code, my project is like a playground I set it up only to study. Sequelize is connecting to the database by calling authenticate but my models are "undefined", so sad...
I will show one image to show my project structure.
my index and product files are like this:
index:
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
produto model
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class produto extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
produto.init({
id: { type: DataTypes.NUMBER,
primaryKey: true},
titulo: DataTypes.STRING,
preco: DataTypes.NUMBER
}, {
sequelize,
modelName: 'produto',
});
return produto;
};
You can try this :
const Produto = require("../models/produto");
It's produto lowercase, half a day on this...
const produto = require('../modelos');
because it's the name of the model that counts... or something like that.
I am new to node js environment and currently I am practicing a crud applicaiton
I am using sequelize as ORM and I have used the mvc structure
npm install --save sequelize
$ npm install --save pg pg-hstore
I am using sequelize cli
npm install --save-dev sequelize-cli
npx sequelize-cli init
It is my migration
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Books', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Books');
}
};
My Model:
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Books extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
Books.init({
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING
}, {
sequelize,
modelName: 'Books',
});
return Books;
};
MY Controller:
exports.allBooks = (req,res)=>{
const bookme = Books(**how to pass sequelize**,**how to pass sequelize datatype**)
var booksJSON = bookme.findAll()
res.json(booksJSON)
console.log(JSON.stringify(booksJSON))
}
I am getting the empty response if I pass the datatypes customly by creating a connection manually to database with sequelize and passing that sequelize to the books models
I think that my mistake is in passing these parameters. What and how shoudld I pass to the Books model
I am importing the books model as follows in my controller:
const Books = require('../models/books.js');
also when i ran the bootstraping that created migrations,models,seeding folders it also created a index.js file in models folder
I have tried passing that too in the parameter to Books model but It gave error
index.js in models folder created by sequelize cli package itself
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
The error I got when I try to pass this db from index.js to Books model in my controller is:
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
^
TypeError: Class constructor model cannot be invoked without 'new'
What should I pass to the parameter and from where?
I am getting response by using aysnc and await. I used second parameter by importing directly from the package
const Sequelize = require('sequelize')
and for first parameter I used the manually created connection.
but it still doesn't clears my concern of actually what parameters were to pass
I have a Sequelize migration script (built off sequelize-cli's initial migration script generated from running sequelize-cli) that dynamically creates tables based on a list of ~100 hardcoded table names imported from a .json file. Thus, it will be tedious and error-prone to hardcode the Sequelize model definitions by hand.
Question: How can we dynamically generate the Sequelize models by reading from the same .json file? I am mainly stuck how we should return multiple Sequelize models using module.exports, based on the model definition file auto-generated from running sequelize-cli model:generate --name Base .... There appears to be a special script models/index.js for reading the model definition file models/base.js.
models/base.js
'use strict';
const universe = require('../config/universe.json');
const generateModel = (sequelize, DataTypes, tableName) => {
const schema = {
name: DataTypes.STRING,
power: DataTypes.DOUBLE,
};
const options = {
timestamps: false,
};
const Model = sequelize.define(tableName, schema, options);
Model.associate = function(models) {
// associations can be defined here
}
return Model;
}
module.exports = (sequelize, DataTypes) => {
models = []
for (let planet in universe) {
for (const species of universe[planet]) {
models.push(generateModel(species));
}
}
return models;
};
app.js
Attempting to load the dynamically created model Human
const Human = require('./models').base.human;
Human.create({name: 'Tom', power: 1.23});
config/universe.json
Example hardcoded data file
{
"earth": [
'human',
'cat',
'dog'
]
}
models/index.js
This file is auto-generated after running sequelize-cli init
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const 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;
module.exports = db;
Background
I am working with Sequelize v4.2 and Express v4.15.2 and attempting to setup the models and associate them with one another. I have struggled to find any working v4.x Sequelize examples even after viewing this Express/Sequelize tutorial as well as the v4 migration docs.
Issue
Currently I am receiving the error below when trying to setup my initial models and associations.
/Users/james/Sites/awesome-app/server/node_modules/sequelize/lib/associations/mixin.js:80
if (!target.prototype || !(target.prototype instanceof this.sequelize.Model)) {
TypeError: Cannot read property 'prototype' of undefined
at Function.<anonymous> (/Users/james/Sites/awesome-app/server/node_modules/sequelize/lib/associations/mixin.js:80:16)
Files/Code
My model setup file (index.js) looks like...
const fs = require('fs');
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 + '/../config/config.json')[env];
let db = {};
let sequelize = undefined;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter((file) => {
return (file.indexOf(".") !== 0) && (file !== 'index.js');
})
.forEach((file) => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
And my first model (address.js) that fails looks like...
module.exports = function(sequelize, DataTypes) {
var Address = sequelize.define('Address', {
street: DataTypes.STRING,
city: DataTypes.STRING,
state: DataTypes.STRING,
zip: DataTypes.STRING,
});
Address.associate = function(models) {
Address.belongsTo(models.attendeeGroup, {
onDelete: 'CASCADE',
foreignKey: {
allowNull: false
},
});
}
return Address;
};
I am looking to setup my database tables and associate various models with one another. Is there another piece of setup I am missing?
My model I wanted to associate with was incorrectly named/capitalized. I had Address.belongsTo(models.attendeeGroup, { where attendeeGroup was camel case, but in fact it needed to be capitalized like AttendeeGroup which is the name of my other model.
My database was successfully created once I changed this model name.