Sequelize ORM: How to statically associate models to db? - javascript

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

Why does sequelize not recognize the Model? TypeError: Cannot read properties of undefined (reading 'findAll')

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;

Importing sequelize model says that it is undefined

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.

getting empty response on sequelize findall from postgres

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

Sequelize Create/Import Dynamically Generated Models

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;

Sequelize & Express model & associate setup

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.

Categories