Does anyone know how to solve this? There is something I am not seeing. To see if the controller was working, I returned the response receiving the request in json, it worked, there was no error.
The problem seems to be with the controller, but the controller...
Edit
Controller
import Post from '../models/Post';
import * as Yup from 'yup';
class PostController {
async store(req, res) {
try {
//Checks if the fields have been filled correctly
const schema = Yup.object().shape({
title: Yup.string()
.required(),
content: Yup.string()
.required()
});
if(!(await schema.isValid(req.body))) {
return res.status(400).json({ error: 'Error 1' });
}
//Abstraction of fields
const { title, content } = req.body;
const createPost = await Post.create(title, content);
if(!createPost) {
return res.json({error: 'Error 2'})
}
//If everything is correct, the information will be registered and returned.
return res.json({
title,
content,
});
}
catch (err) {
console.log("Error: " + err);
return res.status(400).json({error: 'Error 3'});
}
}
}
export default new PostController();
Model:
import Sequelize, { Model } from 'sequelize';
class Post extends Model {
static init(sequelize) {
//Fields registered by the user
super.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
title: Sequelize.STRING,
content: Sequelize.TEXT,
created_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
},
updated_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
},
},
{
sequelize,
tableName: 'posts'
});
return this;
}
}
export default Post;
Migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('posts', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
content: {
type: Sequelize.TEXT,
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
},
updated_at: {
type: Sequelize.DATE,
allowNull: false,
}
});
},
down: (queryInterface) => {
return queryInterface.dropTable('posts');
}
};
The terminal error:
TypeError: Cannot read property 'length' of undefined
You need to define all columns that you put on migration inside your model. As you put allowNull: false, the database needs the column info.
I believe that you can solve adding the columns that you declared on your migration inside your Model and, if you don't wanna to declare those columns on your Controller, add the defaultValue property on those columns.
This will allow to sequelize to insert the appropriate data on those columns. As example: defaultValue: Sequelize.NOW on created_at column.
Another thing that you need to put is the table name, like this (this is one Model that I use inside one of my projects:
static init(sequelize) {
super.init(
{
categoryId: {
type: Sequelize.INTEGER,
primaryKey: true,
field: 'id',
},
dateUpdated: {
type: Sequelize.DATE,
field: 'updated_at',
defaultValue: Sequelize.NOW,
},
// ... other fields here,
},
{
sequelize,
tableName: 'categories',
}
);
}
// ...
}
export default Category;
And, therefore, try to import as Instance, not as a class.
EDIT 1:
Other thing. The error that are in your answer is on line 140 of file lib/model.js (see here on github on the master repo of sequelize).
Looking at this, try to declare your primary key on model if if you didn't yet.
EDIT 2:
In your controller, try this (according to docs):
await Post.create({ title, content });
Try to pass an json object with info that you want to store and not as parameters.
EDIT 3:
You need to import database.js before call the controllers, I had problems in this point (follow a database.js that is working):
// Imports here
import Category from '../app/models/Category';
//...
const models = [
// Models that I want to use
Category,
//...
];
class Database {
constructor() {
this.init();
}
// Load on database init
init() {
this.connection = new Sequelize(databaseConfig);
models.forEach(model => model.init(this.connection));
}
}
export default new Database();
I was having the same problem
The problem with my code was that I was forgetting to add the module name to my database's index.js file inside my models array
eg: const **models** = [User,**Task**]
I found the answer on this post:
https://github.com/sequelize/sequelize/issues/11111#issuecomment-697078832
I had the same problem that Naruto Uzumaki. I forgot to put the connection with the model on the file that initialize the models.
Related
I am trying to create a many to many relationship between user table and role table through userroles table.
After table creation the db looks just fine, I tried pretty much everything I found on the sequelize documentation and previous answers here, nothing seems to work.
I am getting this error: EagerLoadingError [SequelizeEagerLoadingError]: UserRoles is not associated to User!
Any idea of what am I doing wrong ? please help!
class User extends Model {
static associate(models) {
User.belongsToMany(models.Role, {
foreignKey: "user_id",
through:'UserRoles',
as:"users"
});
}
}
User.init(
{
user_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
unique: true,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
phone: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
sequelize,
modelName: "User",
}
);
class Role extends Model {
static associate(models) {
Role.belongsToMany(models.User, {
foreignKey: "role_id",
through:'UserRoles',
as:"roles"
});
}
}
Role.init(
{
role_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
unique:true
},
role_name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
role_desc: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
sequelize,
modelName: "Role",
}
);
class UserRoles extends Model {
static associate(models) {
}
}
UserRoles.init(
{
userroles_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
// user_id: {
// type: DataTypes.UUID,
// defaultValue: DataTypes.UUIDV4,
// },
// role_id: {
// type: DataTypes.UUID,
// defaultValue: DataTypes.UUIDV4,
// },
},
{
sequelize,
modelName: "UserRoles",
}
);
const signup = (req, res) => {
console.log(req.body);
console.log("signup entry");
if (
!req.body.role ||
!req.body.email ||
!req.body.password ||
!req.body.name ||
!req.body.phone
) {
res.status(400).send({
msg: "Please pass role, email, password and name.",
});
} else {
sequelize.models.User.findOne({
where: {
email: req.body.email,
},
})
.then((duplicateemailfound) => {
if (duplicateemailfound) {
console.log(duplicateemailfound);
return res.status(400).json({
success: false,
message: "Email already registered",
});
} else {
let userRole = req.body.role.toLowerCase();
console.log("userRole:", userRole);
sequelize.models.Role.findOne({
where: {
role_name: userRole,
},
})
.then((foundRole) => {
// console.log(foundRole);
if (foundRole == null) {
return res.status(400).json({
success: false,
role: "null or not found",
});
}
// console.log("foundRole", foundRole); // .role_id
let addUser = {
email: req.body.email,
password: req.body.password,
name: req.body.name,
phone: req.body.phone,
role_id: foundRole.role_id,
};
sequelize.models.User.create(addUser, {
include: [{ model: sequelize.models.UserRoles }],
})
.then((newUser) => {
console.log("new user", newUser);
return res.status(201).json({
success: true,
newuser: newUser,
});
})
.catch((error) => {
console.log(error);
res.status(400).json({
success: false,
// message: "Duplicate Email was Found",
error: error.errors[0].message,
error: error,
});
});
})
.catch((error) => {
console.log(error);
res.status(400).json({
error: error,
msg: "bbb",
});
});
}
})
.catch((err) => {
console.log(err);
});
}
};
You create some a class for each Model and extend them with Model class of sequelize, this if fine.
Now, you define a static method inside the class named associate(model) where you define the rule for that class. This is fine because you used static which is required here to since it will be a property of the class, not of an object.
Then you call the initialize method (a in-built method of class Model). In the same way you need to call your defined associate.
Here is a problem, because in the structure that you have now, you can't call that method in it's own class file, becuase you need the other Model to pass it as parameter.
So there are 2 solutions:
Import your User model inside Role model file and call the static method, like this:
const User = require('User')
class Role extends Model {
static associate(model) {
Role.belongsToMany(model, {
foreignKey: "role_id",
through:'UserRoles',
as:"roles"
});
}
}
Role.init(
{
role_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
unique:true
},
role_name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
role_desc: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
sequelize,
modelName: "Role",
}
);
Role.associate(User);
This will use your User model to pass it to the static method and finally to run the belongsToMany
Second solution would be to create an index file for your Models, where you import both of them and you can simply run that belongsToMany there, and then simply import that index file in the main file of your application, something like this:
User.js
const index = require('./../index.js');
const Sequelize = require('sequelize');
const Model = Sequelize.Model;
const sequelize = index.sequelize;
class User extends Model{}
User.init({
username: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
password: {
type: Sequelize.STRING,
allowNull: false
},
role: {
type: Sequelize.STRING,
allowNull: false
}
},{
sequelize,
modelName: 'user'
});
module.exports = {
User: User
}
Role.js will look the same but with your own model.
and index.js would look like this:
const Sequelize = require('sequelize');
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USERNAME, process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: process.env.DB_DIALECT
});
exports.sequelize = sequelize;
const user = require('./models/User');
const role= require('./models/Role');
role.belongsToMany(user, {
foreignKey: "role_id",
through:'UserRoles',
as:"roles"
});
sequelize.sync(user);
sequelize.sync(role);
exports.db = {
user: user,
role: role
}
I have model
model/Caregiver
import { BuildOptions, DataTypes, Model, Sequelize } from 'sequelize';
export interface CaregiverAttributes {
caregiver_id: number | string;
caregiver_notification_preferences?: string;
}
export interface CaregiverModel
extends Model<CaregiverAttributes>,
CaregiverAttributes {}
export type CaregiverStatic = typeof Model & {
new (values?: object, options?: BuildOptions): CaregiverModel;
};
export function CaregiverFactory(sequelize: Sequelize): CaregiverStatic {
return <CaregiverStatic>sequelize.define(
'caregiver',
{
caregiver_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true,
},
caregiver_notification_preferences: {
type: DataTypes.STRING,
allowNull: true,
},
},
{
timestamps: false,
underscored: true,
tableName: 'caregiver',
}
);
}
and associations
Caregiver.belongsToMany(Patient, {
foreignKey: 'caregiver_id',
targetKey: 'caregiver_id',
as: 'Patient',
});
But when I try to get or set
const patients = await caregiver.getPatients();
I have an error: property getPatients does not exist on type CaregiverModel
Maybe someone have the same problem?
Notice: With // #ts-ignore works fine.
Solved
Find this paper https://vivacitylabs.com/setup-typescript-sequelize/ , where it is describe.
I'm trying to bulk insert with associations,
I have this 'Song' model which have one to many relationships with 'Genre' and 'Language' defined with the migrations CLI.
Song:
module.exports = (sequelize, DataTypes) => {
class Song extends Model {
static associate(models) {
// define association here
Song.hasMany(models["Language"])
Song.hasMany(models["Genre"])
}
};
Song.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: DataTypes.STRING,
energy: {type: DataTypes.FLOAT, allowNull: false},
valence: {type: DataTypes.FLOAT, allowNull: false}
}, {
sequelize,
modelName: 'Song',
timestamps: true
});
return Song;
};
Language:
module.exports = (sequelize, DataTypes) => {
class Language extends Model {
static associate(models) {
// define association here
models["Language"].belongsTo(models["Song"])
}
};
Language.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: DataTypes.STRING
}, {
sequelize,
modelName: 'Language',
indexes: [{unique: true, fields: ['name']}]
});
return Language;
};
Genre:
module.exports = (sequelize, DataTypes) => {
class Genre 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
models["Genre"].belongsTo(models["Song"])
}
};
Genre.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: DataTypes.STRING
}, {
sequelize,
modelName: 'Genre',
indexes: [{unique: true, fields: ['name']}]
});
return Genre;
};
I'm trying to bulk insert songs with languages and genres like this:
Song.bulkCreate(songs, {
include: [Genre,Language]
}).then(() => {
const result = {
status: "ok",
message: "Upload Successfully!",
}
res.json(result);
});
each song in the songs array is structured like this:
{
name: "abc",
genres: [{name: "abc"}],
languages: [{name: "English"}],
energy: 1,
valence: 1
}
I'm ending up with a full songs table but genres and languages are empty
What am I doing wrong?
Thanks.
Just in case anyone else got here from a search, starting from version 5.14
Sequelize added the option to use include option in bulkCreate as follows:
await Song.bulkCreate(songsRecordsToCreate, {
include: [Genre,Language]
})
Edit 2nd Feb 2023
As none answered above, as of v5.14.0 the include option is now available on bulkInsert.
Unfortunately bulkCreate does not support include option like create do.
You should use create in a cycle inside a transaction.
const transaction = ...
for (const song of songs) {
await Song.create(song, {
include: [Genre,Language]
}, { transaction })
}
await transaction.commit()
or you can use Promise.all to avoid using for.
I already have my server application written in Node, PostgreSQL, Sequelize using Fastify.
Now I would like to use TypeScript. Can anyone tell me how to begin rewriting my Server application using TypeScript.
Updated
/**
* Keep this file in sync with the code in the "Usage" section
* in /docs/manual/other-topics/typescript.md
*
* Don't include this comment in the md file.
*/
import {
Association, DataTypes, HasManyAddAssociationMixin, HasManyCountAssociationsMixin,
HasManyCreateAssociationMixin, HasManyGetAssociationsMixin, HasManyHasAssociationMixin,
HasManySetAssociationsMixin, HasManyAddAssociationsMixin, HasManyHasAssociationsMixin,
HasManyRemoveAssociationMixin, HasManyRemoveAssociationsMixin, Model, ModelDefined, Optional,
Sequelize, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ForeignKey,
} from 'sequelize';
const sequelize = new Sequelize('mysql://root:asd123#localhost:3306/mydb');
// 'projects' is excluded as it's not an attribute, it's an association.
class User extends Model<InferAttributes<User, { omit: 'projects' }>, InferCreationAttributes<User, { omit: 'projects' }>> {
// id can be undefined during creation when using `autoIncrement`
declare id: CreationOptional<number>;
declare name: string;
declare preferredName: string | null; // for nullable fields
// timestamps!
// createdAt can be undefined during creation
declare createdAt: CreationOptional<Date>;
// updatedAt can be undefined during creation
declare updatedAt: CreationOptional<Date>;
// Since TS cannot determine model association at compile time
// we have to declare them here purely virtually
// these will not exist until `Model.init` was called.
declare getProjects: HasManyGetAssociationsMixin<Project>; // Note the null assertions!
declare addProject: HasManyAddAssociationMixin<Project, number>;
declare addProjects: HasManyAddAssociationsMixin<Project, number>;
declare setProjects: HasManySetAssociationsMixin<Project, number>;
declare removeProject: HasManyRemoveAssociationMixin<Project, number>;
declare removeProjects: HasManyRemoveAssociationsMixin<Project, number>;
declare hasProject: HasManyHasAssociationMixin<Project, number>;
declare hasProjects: HasManyHasAssociationsMixin<Project, number>;
declare countProjects: HasManyCountAssociationsMixin;
declare createProject: HasManyCreateAssociationMixin<Project, 'ownerId'>;
// You can also pre-declare possible inclusions, these will only be populated if you
// actively include a relation.
declare projects?: NonAttribute<Project[]>; // Note this is optional since it's only populated when explicitly requested in code
// getters that are not attributes should be tagged using NonAttribute
// to remove them from the model's Attribute Typings.
get fullName(): NonAttribute<string> {
return this.name;
}
declare static associations: {
projects: Association<User, Project>;
};
}
class Project extends Model<
InferAttributes<Project>,
InferCreationAttributes<Project>
> {
// id can be undefined during creation when using `autoIncrement`
declare id: CreationOptional<number>;
// foreign keys are automatically added by associations methods (like Project.belongsTo)
// by branding them using the `ForeignKey` type, `Project.init` will know it does not need to
// display an error if ownerId is missing.
declare ownerId: ForeignKey<User['id']>;
declare name: string;
// `owner` is an eagerly-loaded association.
// We tag it as `NonAttribute`
declare owner?: NonAttribute<User>;
// createdAt can be undefined during creation
declare createdAt: CreationOptional<Date>;
// updatedAt can be undefined during creation
declare updatedAt: CreationOptional<Date>;
}
class Address extends Model<
InferAttributes<Address>,
InferCreationAttributes<Address>
> {
declare userId: ForeignKey<User['id']>;
declare address: string;
// createdAt can be undefined during creation
declare createdAt: CreationOptional<Date>;
// updatedAt can be undefined during creation
declare updatedAt: CreationOptional<Date>;
}
Project.init(
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: new DataTypes.STRING(128),
allowNull: false
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
},
{
sequelize,
tableName: 'projects'
}
);
User.init(
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: new DataTypes.STRING(128),
allowNull: false
},
preferredName: {
type: new DataTypes.STRING(128),
allowNull: true
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
},
{
tableName: 'users',
sequelize // passing the `sequelize` instance is required
}
);
Address.init(
{
address: {
type: new DataTypes.STRING(128),
allowNull: false
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
},
{
tableName: 'address',
sequelize // passing the `sequelize` instance is required
}
);
// You can also define modules in a functional way
interface NoteAttributes {
id: number;
title: string;
content: string;
}
// You can also set multiple attributes optional at once
type NoteCreationAttributes = Optional<NoteAttributes, 'id' | 'title'>;
// And with a functional approach defining a module looks like this
const Note: ModelDefined<
NoteAttributes,
NoteCreationAttributes
> = sequelize.define(
'Note',
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
title: {
type: new DataTypes.STRING(64),
defaultValue: 'Unnamed Note'
},
content: {
type: new DataTypes.STRING(4096),
allowNull: false
}
},
{
tableName: 'notes'
}
);
// Here we associate which actually populates out pre-declared `association` static and other methods.
User.hasMany(Project, {
sourceKey: 'id',
foreignKey: 'ownerId',
as: 'projects' // this determines the name in `associations`!
});
Address.belongsTo(User, { targetKey: 'id' });
User.hasOne(Address, { sourceKey: 'id' });
async function doStuffWithUser() {
const newUser = await User.create({
name: 'Johnny',
preferredName: 'John',
});
console.log(newUser.id, newUser.name, newUser.preferredName);
const project = await newUser.createProject({
name: 'first!'
});
const ourUser = await User.findByPk(1, {
include: [User.associations.projects],
rejectOnEmpty: true // Specifying true here removes `null` from the return type!
});
// Note the `!` null assertion since TS can't know if we included
// the model or not
console.log(ourUser.projects![0].name);
}
(async () => {
await sequelize.sync();
await doStuffWithUser();
})();
OLD
Using Decorators is something you should avoid as much as possible, they are not ECMAScript standard. They are even consider legacy. It is why I'm going to show you how to use sequelize with typescript.
we just need to follow the docs: https://sequelize.org/v5/manual/typescript.html but as it is not very clear, or at least to me. It took me a while understand it.
There it says that you need to install this tree things
* #types/node
* #types/validator // this one is not need it
* #types/bluebird
npm i -D #types/node #types/bluebird
then let's assume your project looks like so:
myProject
--src
----models
------index.ts
------user-model.ts
------other-model.ts
----controllers
----index.ts
--package.json
Let's create the user model first
`./src/models/user-model.ts`
import { BuildOptions, DataTypes, Model, Sequelize } from "sequelize";
export interface UserAttributes {
id: number;
name: string;
email: string;
createdAt?: Date;
updatedAt?: Date;
}
export interface UserModel extends Model<UserAttributes>, UserAttributes {}
export class User extends Model<UserModel, UserAttributes> {}
export type UserStatic = typeof Model & {
new (values?: object, options?: BuildOptions): UserModel;
};
export function UserFactory (sequelize: Sequelize): UserStatic {
return <UserStatic>sequelize.define("users", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
});
}
Now just to play arrow let's create another-model.ts
`./src/models/another-model.ts`
import { BuildOptions, DataTypes, Model, Sequelize } from "sequelize";
export interface SkillsAttributes {
id: number;
skill: string;
createdAt?: Date;
updatedAt?: Date;
}
export interface SkillsModel extends Model<SkillsAttributes>, SkillsAttributes {}
export class Skills extends Model<SkillsModel, SkillsAttributes> {}
export type SkillsStatic = typeof Model & {
new (values?: object, options?: BuildOptions): SkillsModel;
};
export function SkillsFactory (sequelize: Sequelize): SkillsStatic {
return <SkillsStatic>sequelize.define("skills", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
skill: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
});
}
Our Entities are done. now the db connection.
open ./src/models/index.ts there is where we gonna place the seqelize instance
`./src/models/index.ts`
import * as sequelize from "sequelize";
import {userFactory} from "./user-model";
import {skillsFactory} from "./other-model";
export const dbConfig = new sequelize.Sequelize(
(process.env.DB_NAME = "db-name"),
(process.env.DB_USER = "db-user"),
(process.env.DB_PASSWORD = "db-password"),
{
port: Number(process.env.DB_PORT) || 54320,
host: process.env.DB_HOST || "localhost",
dialect: "postgres",
pool: {
min: 0,
max: 5,
acquire: 30000,
idle: 10000,
},
}
);
// SOMETHING VERY IMPORTANT them Factory functions expect a
// sequelize instance as parameter give them `dbConfig`
export const User = userFactory(dbConfig);
export const Skills = skillsFactory(dbConfig);
// Users have skills then lets create that relationship
User.hasMay(Skills);
// or instead of that, maybe many users have many skills
Skills.belongsToMany(Users, { through: "users_have_skills" });
// the skill is the limit!
on our index.ts add, if you just want to open connection
db.sequelize
.authenticate()
.then(() => logger.info("connected to db"))
.catch(() => {
throw "error";
});
or if you want to create them tables
db.sequelize
.sync()
.then(() => logger.info("connected to db"))
.catch(() => {
throw "error";
});
some like this
import * as bodyParser from "body-parser";
import * as express from "express";
import { dbConfig } from "./models";
import { routes } from "./routes";
import { logger } from "./utils/logger";
import { timeMiddleware } from "./utils/middlewares";
export function expressApp () {
dbConfig
.authenticate()
.then(() => logger.info("connected to db"))
.catch(() => {
throw "error";
});
const app: Application = express();
if (process.env.NODE_ENV === "production") {
app.use(require("helmet")());
app.use(require("compression")());
} else {
app.use(require("cors")());
}
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true, limit: "5m" }));
app.use(timeMiddleware);
app.use("/", routes(db));
return app;
}
Once again the sky is the limit.
If you do this you'll have all the power of the autocomplete.
here an example: https://github.com/EnetoJara/resume-app
Use sequelize-typescript. Convert your tables and views into a class that extends Model object.
Use annotations in classes for defining your table.
import {Table, Column, Model, HasMany} from 'sequelize-typescript';
#Table
class Person extends Model<Person> {
#Column
name: string;
#Column
birthday: Date;
#HasMany(() => Hobby)
hobbies: Hobby[];
}
Create a connection to DB by creating the object:
const sequelize = new Sequelize(configuration...).
Then register your tables to this object.
sequelize.add([Person])
For further reference check this module.
Sequelize-Typescript
as you guys can see my issue is related to the title description, i created a User Model, and a Foto Model in sequelize, basicly a user can shoot many fotos, but each foto can be related to just 1 user.
My User model
"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var Foto = require('./Foto');
module.exports = function (sequelize, DataTypes) {
var User = sequelize.define("User", {
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isUnique: function (value, next) {
var self = this;
User.find({ where: { username: value } })
.then(function (user) {
// reject if a different user wants to use the same username
if (user && self.id !== user.id) {
return next('username already in use!');
}
return next();
})
.catch(function (err) {
return next(err);
});
}
}
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isUnique: function (value, next) {
var self = this;
User.find({ where: { email: value } })
.then(function (user) {
// reject if a different user wants to use the same email
if (user && self.id !== user.id) {
return next('Email already in use!');
}
return next();
})
.catch(function (err) {
return next(err);
});
}
}
},
typeOfUser: {
type: DataTypes.INTEGER,
allowNull:true,
defaultValue:null
},
country: {
type: DataTypes.STRING,
allowNull:true,
defaultValue:null
},
birthDate:{
type: DataTypes.DATEONLY,
allowNull:true,
defaultValue:null
},
reports: {
type: DataTypes.INTEGER,
defaultValue: 0
},
points: {
type: DataTypes.INTEGER,
defaultValue: 0
},
password: {
type: DataTypes.STRING,
allowNull:false
},
numberFotos: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {
classMethods: {
generateHash: function (password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
},
},
instanceMethods: {
validPassword: function (password) {
return bcrypt.compareSync(password, this.password);
}
}
});
User.hasMany(Foto,{as: 'fotos', foreignKey: 'userId'})
return Foto;
}
My foto model
"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var User = require('./User');
module.exports = function (sequelize, DataTypes) {
var Foto = sequelize.define("Foto", {
reports: {
type: DataTypes.INTEGER,
defaultValue: 0
},
image: {
type: DataTypes.STRING,
allowNull: false
},
date: {
type: DataTypes.DATE,
allowNull:true
},
position: {
type: DataTypes.RANGE,
allowNull: true
}
});
Foto.belongsTo(User, {foreignKey: 'userId'});
return Foto;
}
You don't need to declare the association on the Photo Model:
Foto.belongsTo(User, {foreignKey: 'userId'});
When you have a 1:N relation between models you only need to refer the id from the "1" model, on our case the User model, on the "N" model, Photos. So doing:
User.hasMany(Foto,{as: 'fotos', foreignKey: 'userId'})
Will create a column on your Foto table with name "userId" that refer to user table. On this way both models are associate as you want.
You can define relations for both models in one file. It doesn't throw any errors that way.
In your Foto.js, you can try:
...
Foto.belongsTo(User);
User.hasMany(Foto);
return Foto;
I had a similar problem. Sometimes it can be caused because in your index.js or app.js the files are loaded in a specific order, so for example if you have a relationship between A and B, A loads first and references B, and B in turn references A, the error will be thrown inside the B file because A has not been fully defined/executed yet.
The solution to this would be to remove all associations from the model files, and inside your app or index.js require them all, and then define their relationships.
Example
const entities = {
A: require('./src/Entity/A'),
B: require('./src/Entity/B'),
};
entities.A.belongsToMany(entities.B, {through: 'AB'});
entities.B.belongsToMany(entities.A, {through: 'AB'});
So I was getting this error and it took me some time to deal with the bug. I realised I was getting the Error because I was referencing the model wrongly. Sequelize is case sensitive so if you created the model with UpperCase ensure to keep it uniform throughout your referencing.
I would also point out you could try this out instead
User.hasMany(models.Foto ,{as: 'fotos', foreignKey: 'userId'})
It seems you need to define both ends of the relationship in the file containing the 1 part of the 1:many association. That is, the "User" file in your case.
So:
User.hasMany(Foto);
Foto.belongsTo(User);
None of the above solutions worked for my scenario (could work for other setups). I stumbled upon this article which states you have to have the models defined and exported prior to applying the associations. Using a separate extra-setup.js file to define the associations, worked for me.
https://github.com/sequelize/express-example/tree/master/express-main-example
I had lots of issues, but I switched to using the sequelize CLI which generated models in this format, I then found creating associations a lot easier as the index file took care of everything and the static associate({ PersonalDetail }) that is in the model itself already requires your models in one place all you need to do is deconstruct them, so no need to require anything at the top of the file.
This youtube video really helped me out... https://www.youtube.com/watch?v=3qlnR9hK-lQ
'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
class User 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({ PersonalDetail }) {
// define association here
this.hasMany(PersonalDetail, {
foreignKey: 'userId',
//as: 'personalDetails',
})
}
}
User.init(
{
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
moredata below: {
type: DataTypes.STRING,
allowNull: false,
},
//createdAt/updatedAt is defined in migration and updated automatically
},
{
sequelize,
tableName: 'users',
modelName: 'User',
}
)
return User
}
I got the same type issue. All mappings were done perfectly as explained in the document.
Yet, I received the issue regarding the association.
Reason is given by Dorian in this forum.
https://stackoverflow.com/a/60760296/16790144
My approach:
models/company.js
const company = sequelize.define("company",{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
companyName: {
type: DataTypes.STRING,
allowNull: false,
}
});
export default company;
models/client.js
const Client = sequelize.define("client", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
}
});
export default Client;
models/clientCompany.js
const clientCompany = sequelize.define("client_company",{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
companyId: {
type: DataTypes.INTEGER
},
clientId: {
type: DataTypes.INTEGER
}
});
export default clientCompany;
models/index.js
import Company from './company';
import Client from './client';
import ClientCompany from './clientCompany';
Company.belongsToMany(Client, { through : ClientCompany });
Client.belongsToMany(Company, { through : ClientCompany });
export {
Company,
Client,
ClientCompany,
};
handler.js
This file contains the business logic.
import { Client, Company } from '../../models';
const company = await Company.findOne({
where: { id: companyId },
include: Client,
});