Sequelize error using association on n:m related objects - javascript

I am using nodeJS, express (4.17.1), sequelize (5.21.4) and mysql (mysql2 v2.1.0) for a current project.
In my database I have three tables Filter, Element and FilterElement. If I query data from database from Filter or Element table separatly I get the result of objects with data. If I want to use "connecting" table FilterElement I get this error {"name":"SequelizeEagerLoadingError"}
EagerLoadingError [SequelizeEagerLoadingError]: filter_element is not
associated to filters_new!
What is wrong with my code?
These are my sequelize objects codes.
Filter.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const Filter = db.define('filters_new', {
Model:{
type: Sequelize.STRING,
primaryKey: true,
allowNull: false
}
},
{
timestamps: false,
freezeTableName: true
}
);
Filter.associate = function(models) {
Filter.belongsToMany(models.Element, {
through: models.FilterElement,
as: 'filter',
foreignKey: 'FilterHousingModel'
});
};
module.exports = Filter;
Element.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const Element = db.define('filter_element', {
idfilter_element:{
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false
},
ElementName:{
type: Sequelize.STRING,
}
},
{
timestamps: false,
freezeTableName: true
}
);
Element.associate = function(models) {
Element.belongsToMany(models.Filter, {
through: models.FilterElement,
as: 'element',
foreignKey: 'FilterElementId'
});
};
module.exports = Element;
FilterElemnt.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const FilterElement = db.define('filters_new', {
idfilter_filterelement:{
type: Sequelize.STRING,
primaryKey: true,
allowNull: false,
autoincrement: true
},
FilterHousingModel: {
type: Sequelize.STRING
},
FilterElementId: {
type: Sequelize.INTEGER
}
},
{
timestamps: false,
freezeTableName: true
}
);
module.exports = FilterElement;
If I call this function, I do get the desired result of data from database.
listFiltersOnly(req, res) {
return filter.findAll()
.then((filters) => {
res.status(200).send(filters);
})
.catch(err => {
console.log(err);
res.status(400).send(err);
});
}
then if I call function list I get the error mentioned up EagerLoadingError
list(req, res) {
return filter.findAll({
include: [{
model: element,
as: 'element'
}],
})
.then((filters) => {
console.log(filters);
res.status(200).send(filters);
})
.catch(err => {
console.log(err);
res.status(400).send(err);
});
}
Looking for some suggjestions where might be the problem?

#RatulSharker I removed the asociation from the model and added it where the models are implemented in the controller and now I do get some results.
Filter.belongsToMany(FilterElement, {
through: FilterFilterElement,
foreignKey: 'FilterHousingModel'
});
FilterElement.belongsToMany(Filter, {
through: FilterFilterElement,
foreignKey: 'FilterElementId'
});
Thank you #Ratul Sharker

Related

Node.js, Sequelize, cannot convert undefined or null to object

I'm working on an API and have a special problem. When a make a GET request, i received my JSON Data but the server crash with an error :
for (const key of Object.keys(this.constructor._attributeManipulation)) {
TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
at Timeout._onTimeout (/Users/quentin/O'Clock/motogpapi/node_modules/sequelize/lib/model.js:83:34)
at listOnTimeout (node:internal/timers:564:17)
at process.processTimers (node:internal/timers:507:7)
I can't undersant origin of this crash. you can find below the code. Is it possible this problem due to as wrong data into db ?
Model team.js:
const { DataTypes, Model } = require("sequelize");
const sequelize = require("../database/client");
class Teams extends Model {}
Teams.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
constructorId: {
type: DataTypes.INTEGER,
allowNull: false
},
isOfficial: {
type: DataTypes.BOOLEAN,
allowNull: false
},
championshipId: {
type: DataTypes.INTEGER,
allowNull: false
},
}, {
sequelize,
tableName: "team"
});
module.exports = Teams;
Model Constructor.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("../database/client");
class Constructors extends Model {}
Constructors.init({
name: {
type: DataTypes.STRING,
allowNull: false
},
model: {
type: DataTypes.STRING,
allowNull: false
},
engine: {
type: DataTypes.STRING,
allowNull: false
},
}, {
sequelize,
tableName: "constructor"
});
module.exports = Constructors;
Model Index.js i used for associations
const Teams = require("./teams");
const Championships = require("./championships");
const Constructors = require("./constructors");
Constructors.hasMany(Teams, {
foreignKey: "constructorId",
as: "teamsList"
});
Teams.belongsTo(Constructors, {
foreignKey: "constructorId",
as: "constructor"
});
Championships.hasMany(Teams, {
foreignKey: "championshipId",
as: "teamsList"
});
Teams.belongsTo(Championships, {
foreignKey: "championshipId",
as: "championship"
});
module.exports = {
Teams,
Championships,
Constructors
};
The Controller :
const { Teams } = require("../models");
const teamsController = {
async getAllTeams(_, response) {
try {
const teamsList = await Teams.findAll({
include: ["constructor", "championship"]
});
response.json(teamsList);
} catch (error) {
console.log(error);
}
}
};
module.exports = teamsController;
And database/client.js
require("dotenv").config();
const { Sequelize } = require("sequelize");
const sequelize = new Sequelize(process.env.PG_URL, {
define: {
underscored: true
}
});
(async () => {
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.");
} catch (error) {
console.error("Unable to connect to the database:", error);
}
})();
module.exports = sequelize;

I can't insert data into a table in Sequelize (foreign keys specifically)

So I'm using Sequelize for my PostgreSQL database on my JavaScript app. I have 4 models (Users, Posts, Likes, and FollowingsFollowers). My Users model works fine, it doesn't have any foreign keys so I'm able to create and find data with no problems whatsoever. However, my Posts model has 2 foreign keys (user_id and parent_id). user_id references the primary key (id) from the Users table and parent_id references the primary key (id) from itself (the Posts table). When I try to insert data into the Posts table I'm able to insert data on the regular fields, but the foreign keys are simply ignored.
Here is my database connection:
const Sequelize = require('sequelize');
const API = require('../../client/public/config.js');
const db = new Sequelize(API.elephantSqlUrl);
db.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch((err) => {
console.error('Unable to connect to the database:', err);
});
module.exports = db;
Here is my Users model:
const Sequelize = require('sequelize');
const db = require('../db.js');
const Users = db.define('users', {
username: {
type: Sequelize.STRING,
unique: true
},
bio: Sequelize.STRING,
profile_picture: Sequelize.STRING
});
module.exports = Users;
Here is my Posts model:
const Sequelize = require('sequelize');
const db = require('../db.js');
const Posts = db.define('posts', {
type: Sequelize.INTEGER,
body: Sequelize.STRING,
likesCount: {
type: Sequelize.INTEGER,
defaultValue: 0
}
});
module.exports = Posts;
Here is where I define the foreign keys and sync my database:
const db = require('./db.js');
const Users = require('./models/users.js');
const Posts = require('./models/posts.js');
const Likes = require('./models/likes.js');
const FollowingsFollowers = require('./models/followingsFollowers.js');
Posts.belongsTo(Users, { foreignKey: 'user_id' });
Users.hasMany(Posts, { foreignKey: 'user_id' });
Posts.belongsTo(Posts, { foreignKey: 'parent_id' });
Posts.hasMany(Posts, { foreignKey: 'parent_id' });
Likes.belongsTo(Posts, { foreignKey: 'post_id' });
Posts.hasMany(Likes, { foreignKey: 'post_id' });
Likes.belongsTo(Users, { foreignKey: 'user_id' });
Users.hasMany(Likes, { foreignKey: 'user_id' });
FollowingsFollowers.belongsTo(Users, { foreignKey: 'following_id' });
Users.hasMany(FollowingsFollowers, { foreignKey: 'following_id' });
FollowingsFollowers.belongsTo(Users, { foreignKey: 'follower_id' });
Users.hasMany(FollowingsFollowers, { foreignKey: 'follower_id' });
db.sync({ force: true })
.then(() => {
console.log('db synced');
})
.catch(() => {
console.log('error syncing db');
});
and this is where I try to add a Post:
const addPost = (username, post) => {
return new Promise((resolve, reject) => {
Users.findOne({ where: { username: username } })
.then((user) => {
post.user_id = user.id;
Posts.create()
.then((created) => {
resolve();
});
})
.catch((err) => {
reject(err);
});
});
};
When I call this function with a username and an object with "type" and "body" keys, a Post is created. However, the Post contains an "id", a "type", a "body", a "likesCount", a "createdAt", and an "updatedAt" fields. The "user_id" field never gets added in there.
I don't know if this is gonna solve your problem, but you don't pass any parameter to create() method. post object is passed to function, enriched with user_id and... ignored.
Shouldn't it be like this?:
(...)
Posts.create(post)
(...)
I was able to solve it. My solution was to add foreign key relations on my model files, like so:
const Sequelize = require('sequelize');
const Users = require('./users.js');
const db = require('../db.js');
const Posts = db.define('posts', {
type: Sequelize.INTEGER,
body: Sequelize.STRING,
likesCount: {
type: Sequelize.INTEGER,
defaultValue: 0
}
});
Posts.belongsTo(Users, { foreignKey: 'user_id' });
Posts.belongsTo(Posts, { foreignKey: 'parent_id' });
module.exports = Posts;
and then for the file where i sync my db, thats all i would do, like so:
const db = require('./db.js');
const Users = require('./models/users.js');
const Posts = require('./models/posts.js');
const Likes = require('./models/likes.js');
const FollowingsFollowers = require('./models/followingsfollowers.js');
db.sync({ force: true })
.then(() => {
console.log('db synced');
})
.catch(() => {
console.log('error syncing db');
});
1. Add user_id as foreign key in posts model and other models where realtion with users required.
2.Define your Posts models as:
const Posts = db.define('posts', {
type: Sequelize.INTEGER,
user_id: Sequelize.INTEGER,
body: Sequelize.STRING,
likesCount: {
type: Sequelize.INTEGER,
defaultValue: 0
}
});
3. Remove Posts.belongsTo(Posts, { foreignKey: 'parent_id' }); not required

Stuck with Sequelize create

I have an issue while trying to add new records into my database.
So I have this code:
const schema = require('./Labels.schema');
const Labels = sequelize.define('labels', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
user: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'user'
},
code: {
type: Sequelize.STRING,
allowNull: false,
field: 'code'
},
name: {
type: Sequelize.STRING,
allowNull: false,
field: 'name'
}
},
{
tableName: 'labels'
timestamps: false
});
Labels.createLabel = async (params) => {
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
params.user = process.env.USER_ID;
const res = joi.validate(params, schema.create);
if(!res) {
Labels.create(params).then(data => {
console.log('test log');
});
} else {
throw new Error(res);
}
};
This is just a basic model of the record that needs to be stored.
I have tried some varients with the create function, sync, async, within try catch. But I just can't get any output what-so-ever. Even if I do a console.log after the create, it doesn't log. So it seems like it gets blocked somehow. That's why I put the sequelize.authenticate to test the connection, but even that doesn't give me any result.
I fairly new to Sequelize, so any help would be highly appreciated!

NodeJS Sequalize Table1 is not associated to Table2

I have two tables table1 and table2. i want to get relational data. I gone through this URL which is same as the my error but that solution is not work for me
module.exports = function (sequelize, DataTypes) {
var table1 = sequelize.define("table1", {
table1Id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
image: {type: DataTypes.STRING},
}, {
timestamps: true,
classMethods: {
associate: function (models) {
table1.belongsTo(models.table2, {
onDelete: "CASCADE",
foreignKey: {
name: "table2Id",
notEmpty: false
}
});
}
}
});
return table1;
};
and another is :
module.exports = function (sequelize, DataTypes) {
var table2 = sequelize.define("table2", {
table2Id: {type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true},
name: {type: DataTypes.STRING},
}, {
timestamps: true,
classMethods: {
associate: function (models) {
table2.hasMany(models.table1, {
onDelete: "CASCADE",
foreignKey: {
name: "table1Id",
notEmpty: false
}
});
}
}
});
return table2;
};
then in controllers:
models.table2.findById(req.params.id, {
include: [{model: models.table1}]
}).then(function (data) {
}).catch(Sequelize.ValidationError, function (err) {
return res.status(422).send(err.errors);
}).catch(function (err) {
console.log(err.message,"err.message")
return res.status(400).send({
message: err.message
});
});
and i got error that Table1 is not associated to Table2
If you are on sequelize >4
The way association are defined is changed.
Instead of defining association as
const Model = sequelize.define('Model',
{ ... },
{ classMethods: { associate: function (model) {...} }
});
They are now defined as
const Model = sequelize.define('Model', { ... });
// Class Method
Model.associate = function (models) { ...associate the models };
This could also justify why it seems to work on one machine and not the other.

Two models: Post and Tag, how can I establish a many to many relationship using Mongoose?

I currently have two models: Post and Tag.
Here is the post model:
'use strict';
import mongoose from 'mongoose';
let PostSchema = new mongoose.Schema({
url_path: {
type: String,
required: true,
trim: true,
},
title: {
type: String,
required: true,
trim: true,
},
body: {
type: String,
required: true,
trim: true,
},
user_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
tags: [{
tag_id: mongoose.Schema.Types.ObjectId,
text: String,
}],
date_created: {
type: Date,
required: true,
trim: true,
},
date_modified: {
type: Date,
required: true,
trim: true,
},
});
module.exports = mongoose.model('Post', PostSchema);
and the tag model:
'use strict';
import mongoose from 'mongoose';
let TagSchema = new mongoose.Schema({
text: {
type: String,
required: true,
unique: true,
lowercase: true,
trim: true,
},
});
module.exports = mongoose.model('Tag', TagSchema);
My end goal is to be able to send a get request, to a route where part of the route is the _id of a given tag (for ex: /tag/:tag_id/posts), and get back a list of all the posts with that tag.
I don't believe I am going about doing this in the best possible manner (I am new to mongoose) but currently I am able to send a post request to a route (/posts/:post_id/tags) and add a tag to the post (which creates the tag if the tag doesn't already exist as an instance of the Tag model)
Here is the tag controller which handles the creation of the tag, and the addition of any tags to posts
'use strict';
import Tag from './../models/Tag';
import Post from './../models/Post';
module.exports.create = (req, res) => {
Tag.findOne({
text: req.body.text,
})
.then(tag => {
if (tag === null) {
let newtag = new Tag({
text: req.body.text,
});
newtag.save();
return newtag;
} else {
return tag;
}
})
.then(tag => {
Post.findById(req.params.post_id)
.then(post => {
post.tags.push(tag);
post.save();
res.json({
post: post,
});
});
});
};
module.exports.list = (req, res) => {
Post.findById(req.params.post_id)
.then(post => {
res.json({
post_tags: post.tags,
});
});
};
module.exports.getPosts = (req, res) => {
let tagtext;
let tagID;
Tag.findById(req.params.tag_id)
.then(tag => {
if (tag === null) {
res.send('no posts');
} else {
tagID = tag._id;
tagtext = tag.text;
}
});
Post.find({
'tags._id': tagID,
})
.then(posts => {
res.json({
posts: posts,
});
});
};
module.exports.getPostsWithTag = (req, res) => {
Post.find({ tags.tag_id: req.params.tag_id }, ...);
}
based on information from this post Find document with array that contains a specific value

Categories