Wednesday, May 15, 2024
 Popular · Latest · Hot · Upcoming
155
rated 0 times [  158] [ 3]  / answers: 1 / hits: 7674  / 4 Years ago, sat, april 11, 2020, 12:00:00

Currently I realize an API using Node Js 13 and the ORM Sequelize v5 and all this in ES6 (via type: module in package.json).



In this project there is a problem when I try to use associations.



I have three models which are associated: author.js, authorbook.js and book.js .



author.js:



import Sequelize from 'sequelize';
import AuthorBook from './authorbook.js';
import dotenv from 'dotenv';

dotenv.config();

const sequelize = new Sequelize(
process.env.DB_DATABASE, process.env.DB_USERNAME, process.env.DB_PASSWORD,{
host: process.env.DB_HOST,
dialect: 'mysql'
}
);

export default class Author extends Sequelize.Model {}
Author.init({
firstName: {
firstName: false,
type: Sequelize.STRING(100)
},
lastName: {
allowNull: false,
type: Sequelize.STRING(100)
}
}, { sequelize });

Author.hasMany(AuthorBook, {
onUpdate: 'CASCADE'
});


book.js:



import Sequelize from 'sequelize';
import AuthorBook from './authorbook.js';
import dotenv from 'dotenv';

dotenv.config();

const sequelize = new Sequelize(
process.env.DB_DATABASE, process.env.DB_USERNAME, process.env.DB_PASSWORD,{
host: process.env.DB_HOST,
dialect: 'mysql'
}
);

export default class Book extends Sequelize.Model {}
Book.init({
title: {
firstName: false,
type: Sequelize.STRING(100)
}
}, { sequelize });

Book.hasMany(AuthorBook, {
onUpdate: 'CASCADE'
});


authorbook.js:



import Sequelize from 'sequelize';
import Author from './author.js';
import Book from './book.js';
import dotenv from 'dotenv';

dotenv.config();

const sequelize = new Sequelize(
process.env.DB_DATABASE, process.env.DB_USERNAME, process.env.DB_PASSWORD,{
host: process.env.DB_HOST,
dialect: 'mysql'
}
);

export default class AuthorBook extends Sequelize.Model {}
AuthorBook.init({
authorId: {
type: Number,
allowNull: false
},
bookId: {
type: Number,
allowNull: false
},
}, { sequelize });

AuthorBook.belongsTo(Author, { foreignKey: 'authorId'});
AuthorBook.belongsTo(Book, { foreignKey: 'bookId'});


Here is the error I get when I run the cmd node src/server.js:



(node:23142) ExperimentalWarning: The ESM module loader is experimental.
file:///Users/alexandre/Documents/project/server/src/db/models/.js:18
Author.hasMany(AuthorBook, {
^

ReferenceError: Cannot access 'AuthorBook' before initialization
at file:///Users/alexandre/Documents/project/server/src/db/models/author.js:38:22
at ModuleJob.run (internal/modules/esm/module_job.js:110:37)
at async Loader.import (internal/modules/esm/loader.js:176:24)


Someone can help me ?


More From » node.js

 Answers
13

The error means there are circular references between your modules. You should put the models in a module like index.ts and make the associations here. Please pay attention to my file directory structure:



E.g.



./models/book.ts:



import Sequelize from 'sequelize';
import { sequelize } from '../../../db';

export default class Book extends Sequelize.Model {}
Book.init(
{
title: {
allowNull: false,
type: Sequelize.STRING(100),
},
},
{ sequelize, modelName: 'books' },
);


./models/author.ts:



import Sequelize from 'sequelize';
import { sequelize } from '../../../db';

export default class Author extends Sequelize.Model {}
Author.init(
{
firstName: {
allowNull: false,
type: Sequelize.STRING(100),
},
lastName: {
allowNull: false,
type: Sequelize.STRING(100),
},
},
{ sequelize, modelName: 'authors' },
);


./models/authorbook.ts:



import Sequelize from 'sequelize';
import { sequelize } from '../../../db';

export default class AuthorBook extends Sequelize.Model {}
AuthorBook.init(
{
authorId: {
type: Sequelize.INTEGER,
allowNull: false,
},
bookId: {
type: Sequelize.INTEGER,
allowNull: false,
},
},
{ sequelize, modelName: 'authorbooks' },
);


./models/index.ts:



import Author from './author';
import Book from './book';
import AuthorBook from './authorbook';

Author.hasMany(AuthorBook, {
onUpdate: 'CASCADE',
});
Book.hasMany(AuthorBook, {
onUpdate: 'CASCADE',
});
AuthorBook.belongsTo(Author, { foreignKey: 'authorId' });
AuthorBook.belongsTo(Book, { foreignKey: 'bookId' });

export { Author, Book, AuthorBook };


Now, we can use these models.



index.ts:



import { Author, AuthorBook, Book } from './models';
import { sequelize } from '../../db';
import faker from 'faker';

(async function test() {
try {
await sequelize.sync({ force: true });
// seed
const author = await Author.create({
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
});
const book = await Book.create({
title: faker.lorem.words(3),
});
await AuthorBook.create({ authorId: author.id, bookId: book.id });
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();


The execution results:



Executing (default): DROP TABLE IF EXISTS authorbooks CASCADE;
Executing (default): DROP TABLE IF EXISTS books CASCADE;
Executing (default): DROP TABLE IF EXISTS authors CASCADE;
Executing (default): DROP TABLE IF EXISTS authors CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS authors (id SERIAL , firstName VARCHAR(100) NOT NULL, lastName VARCHAR(100) NOT NULL, PRIMARY KEY (id));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'authors' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS books CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS books (id SERIAL , title VARCHAR(100) NOT NULL, PRIMARY KEY (id));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'books' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS authorbooks CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS authorbooks (id SERIAL , authorId INTEGER NOT NULL REFERENCES authors (id) ON DELETE CASCADE ON UPDATE CASCADE, bookId INTEGER NOT NULL REFERENCES books (id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (id));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'authorbooks' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO authors (id,firstName,lastName) VALUES (DEFAULT,$1,$2) RETURNING *;
Executing (default): INSERT INTO books (id,title) VALUES (DEFAULT,$1) RETURNING *;
Executing (default): INSERT INTO authorbooks (id,authorId,bookId) VALUES (DEFAULT,$1,$2) RETURNING *;


check the database:



node-sequelize-examples=# select * from authors;
id | firstName | lastName
----+-----------+----------
1 | Laron | Deckow
(1 row)

node-sequelize-examples=# select * from books;
id | title
----+-------------------------
1 | facilis molestias sequi
(1 row)

node-sequelize-examples=# select * from authorbooks;
id | authorId | bookId
----+----------+--------
1 | 1 | 1
(1 row)


Dependencies versions: sequelize: ^5.21.3, postgres:9.6



source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/61163520


[#4192] Wednesday, April 8, 2020, 4 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kylanalis

Total Points: 438
Total Questions: 85
Total Answers: 102

Location: Barbados
Member since Sun, Nov 27, 2022
1 Year ago
kylanalis questions
Sat, Oct 2, 21, 00:00, 3 Years ago
Tue, Oct 13, 20, 00:00, 4 Years ago
Thu, Feb 13, 20, 00:00, 4 Years ago
Tue, Jan 7, 20, 00:00, 4 Years ago
Thu, Jan 2, 20, 00:00, 4 Years ago
;