How can I sequelize belongsToMany? - node.js

How can I belongsToMany two different columns in the same table with the ID in a different table?
User Model
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
firstName: {
type: DataTypes.STRING(255)
}
Message Model
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
userId1: {
type: DataTypes.UUID
},
userId2: {
type: DataTypes.UUID
}
belongsTo
thisModel.belongsTo(userModel, {
foreignKey: 'userId1',
foreignKey: 'userId2' // How can add this one here
})

Suppose your case is a message has a sender(userId1) and a receiver(userId2). Below code will work for this case:
const User = sequelize.define('user', {
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
firstName: {
type: DataTypes.STRING(255)
}
});
const Message = sequelize.define('message', {
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
text: {
type: DataTypes.STRING
},
userId1: {
type: DataTypes.UUID
},
userId2: {
type: DataTypes.UUID
}
});
// define the association
User.hasMany(Message, {
foreignKey: 'userId1',
as: 'sender'
})
User.hasMany(Message, {
foreignKey: 'userId2',
as: 'receiver'
})
Message.belongsTo(User, {
foreignKey: 'userId1',
as: 'sender'
});
Message.belongsTo(User, {
foreignKey: 'userId2',
as: 'receiver'
});
// Example using the association
sequelize.sync({
force: true
})
.then(async () => {
// create some users
await User.bulkCreate([
{ firstName: 'user1'},
{ firstName: 'user2'}
])
const users = await User.findAll()
const [user1, user2] = users
const message = await Message.create({
text: 'hello'
})
await message.setSender(user1)
await message.setReceiver(user2)
console.log(message)
})

Related

postgres returns another table column while inserting data in sequelize

When I try to insert new category, I got this error:
error: column "image" does not exist
sql: 'INSERT INTO "Categories" ("id","createdAt","updatedAt") VALUES (DEFAULT,$1,$2) RETURNING "id","image","title","createdAt","updatedAt";'
The problem is that it doesn't insert name and other values and returns columns belong to post table.
My guesses are the problem of sequelize-cli and sequelize version or missing something in models or migrations.
I only insert values into name, createdAt and updatedAt column:
await Category.create({
name: req.body.name,
createdAt: new Date(),
updatedAt: new Date()
});
My category model:
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Category extends Model {
static associate(models) {
Category.hasMany(models.Post, { as: "posts", foreignKey: "categoryId" });
}
}
Category.init(
{
name: DataTypes.STRING
},
{
sequelize,
modelName: "Category"
}
);
return Category;
};
My Post Model:
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Post extends Model {
static associate(models) {
Post.belongsTo(models.Category, { foreignKey: "categoryId", onDelete: "CASCADE", as: "category" });
}
}
Post.init(
{
title: DataTypes.STRING,
image: DataTypes.STRING,
content: DataTypes.TEXT,
categoryId: DataTypes.INTEGER
},
{
sequelize,
modelName: "Post"
}
);
return Post;
};
Post migration:
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable("Posts", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
title: {
type: Sequelize.STRING
},
image: {
type: Sequelize.STRING
},
content: {
type: Sequelize.TEXT
},
categoryId: {
type: Sequelize.INTEGER,
allowNull: false,
onDelete: "CASCADE",
references: {
model: "Categories",
key: "id"
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
Category migration:
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable("Categories", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
I couldn't find solution for this, therefor I used sequelize.query

How to filter in postgresSQL and nodejs

I am trying to search user that not in the team yet to invite them but right now my function is searching user that in the team only. So now how can I implement the function to search user that not in the team yet.
Here is my following code:
exports.searchUserToInvite = async (req, res) => {
// Grab query
const query = req.params.q;
const publicTeamId = req.params.id;
const teamId = await getTeamId(publicTeamId);
// Get team data based on id
// Search for users
const usersFound = await models.User.findAll({
where: {
[Op.or]: [
{
fullname: {
[Op.iLike]: "%" + query + "%",
},
},
],
},
attributes: [
"fullname",
"public_user_id",
"institution",
"location",
"webpage",
"linkedin",
"major",
"picture",
"verifiedDT",
],
include: [
{
model: models.Rating,
attributes: ["skillset_rating", "team_member_rating"],
},
{
model: models.Skill,
attributes: ["skill"],
},
{
model: models.Team,
attributes: ["status"],
where: {
id: teamId,
},
},
],
});
// Run searches
const searchData = await Promise.all([usersFound]);
// Return results
res.status(200).json(searchData);
};
Update add following code model User:
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
"User",
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
allowNull: false,
},
fullname: {
type: DataTypes.STRING,
allowNull: false,
},
passwordhash: DataTypes.STRING,
institution: DataTypes.STRING,
bio: DataTypes.STRING,
creator_user_id: DataTypes.UUID,
public_user_id: DataTypes.STRING,
picture: DataTypes.STRING(300),
email: { type: DataTypes.STRING, unique: true },
service: DataTypes.STRING,
gender: DataTypes.STRING,
age: DataTypes.INTEGER ,
altId: DataTypes.STRING,
location: DataTypes.STRING,
mergedTo: DataTypes.UUID,
document: DataTypes.STRING,
webpage: DataTypes.STRING,
linkedin: DataTypes.STRING,
signupIP: DataTypes.STRING,
major: DataTypes.STRING,
verifiedDT: DataTypes.DATE,
couponsUsed: DataTypes.ARRAY(DataTypes.STRING),
teamCredits: DataTypes.INTEGER ,
resetToken: DataTypes.STRING,
resetTokenExpires: DataTypes.DATE,
uniqueToken: DataTypes.STRING,
expireToken: DataTypes.DATE,
},
{
tableName: "Users",
timestamps: true,
indexes: [
{
unique: false,
fields: ["email", "id", "fullname", "public_user_id"],
},
],
}
);
User.associate = function (models) {
User.belongsToMany(models.Skill, { through: models.UserSkills });
User.hasMany(models.Team, {
foreignKey: "creatorId",
});
User.hasMany(models.Membership, {
foreignKey: "memberId",
});
User.hasMany(models.Rating, {
foreignKey: "raterId",
});
User.hasMany(models.Rating, {
foreignKey: "rateeId",
});
User.hasMany(models.InvitesApplications, {
foreignKey: "senderId",
});
User.hasMany(models.Message, {
foreignKey: "userID"
});
};
return User;
};
How can I implement my function?
Updated add model Membership in question:
"use strict";
module.exports = (sequelize, DataTypes) => {
const Membership = sequelize.define(
"Membership",
{
interests: DataTypes.STRING,
contributions: DataTypes.STRING,
authorization: DataTypes.STRING,
status: DataTypes.STRING,
application_letter: DataTypes.STRING,
date_applied: DataTypes.DATE,
date_joined: DataTypes.DATE,
date_departed: DataTypes.DATE
},
{ tableName: "Memberships", timestamps: true }
);
Membership.associate = function(models) {
Membership.belongsTo(models.User, {
foreignKey: "memberId"
});
Membership.belongsTo(models.Team, {
foreignKey: "teamId"
});
Membership.belongsTo(models.Role, {
foreignKey: "roleId"
});
Membership.hasMany(models.Rating, {
foreignKey: "membershipId"
});
};
return Membership;
};
Updated add model User in question:
you need to apply not equal to in where clause.
where: {
id: {[Op.ne]: teamId},
},

Sequelize Association Error: A is not associated to B

I'm using Sequelize for my Postgres database. I have a Messages and a Users table; a user has many messages and a message belongs to a user. I've defined my models as follows:
User
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
}, {
modelName: 'User',
});
User.associate = (models) => {
User.hasMany(models.Message, { foreignKey: 'userId', as: 'Messages' })
}
return User;
};
Message
module.exports = (sequelize, DataTypes) => {
const Message = sequelize.define('Message', {
content: {
allowNull: false,
type: DataTypes.STRING,
validate: {
len: [1, 248],
}
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id'
}
},
likes: {
defaultValue: 0,
type: DataTypes.INTEGER
},
}, {
modelName: 'Message',
});
Message.associate = (models) => {
Message.belongsTo(models.User, { foreignKey: 'userId', as: 'User', onDelete: 'CASCADE' })
}
return Message;
};
And here's how I'm testing them:
User.create({
firstName: 'Test', lastName: 'Test', email: 'test#test.com', password: '87654321'
}).then((newUser) => {
console.log(newUser.get())
})
Message.bulkCreate([
{ content: "Hello", likes: 0, userId: 1 },
{ content: "Hello World", likes: 0, userId: 1 },
{ content: "Hello World 2", likes: 123, userId: 1 }
])
.then((newMessages) => {
console.log(newMessages)
})
const findAllWithMessages = async () => {
const users = await User.findAll({
include: [{
model: Message
}]
});
console.log(JSON.stringify(users, null));
}
Here's my Migration file to create the users table:
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
And the messages table:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Messages', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id',
as: 'userId',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
},
content: {
allowNull: false,
type: Sequelize.STRING,
validate: {
len: [1, 248],
}
},
likes: {
defaultValue: 0,
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Messages');
}
};
I'm registering my models and associations using Sequelize CLI out of the box code when you run sequelize-cli init:
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);
}
});
const User = require('./user')(sequelize, Sequelize.DataTypes)
const Message = require('./message')(sequelize, Sequelize.DataTypes)
db.models = { User, Message }
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.DataTypes = Sequelize.DataTypes
module.exports = db;
Finally, when I run findAllWithMessages(), I'm getting this error UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: Message is not associated to User!
I can confirm that the models are being created and that the association between the models work because when I run a raw SQL query select * from "Messages" as a inner join "Users" as b on b.id = a."userId" where a."userId"=1; I get the correct results. So I'm assuming its a Sequelize thing.
Any help is appreciated!
I've found my issue. In the code I was importing from db.models = { User, Message } so this block Object.keys(db).forEach(modelName)... wasn't associating the models I was using. Essentially, I was calling the .associate function on instances of the models that were different than the instances I was using.

Sequelize many to many "degree is not associated to doctor"

I have two models Doctor and Degree with many to many relationship.
Doctor model:
const Doctor = _sequelize.define('doctor', {
fullname: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
gender: {
type: Sequelize.STRING
},
address: {
type: Sequelize.STRING
},
phone: {
type: Sequelize.STRING
},
avatarurl: {
type: Sequelize.STRING
},
active: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
license: {
type: Sequelize.STRING
}
},{
timestamps: false,
tableName: 'doctor'
})
Doctor.associate = (models) => {
Doctor.belongsToMany(model.degree, { through: 'doctor_degree', foreignKey: 'doctor_id',as: 'degree' })
}
Degree model:
const Degree = _sequelize.define('degree', {
name: {
type: Sequelize.STRING
}
},{
timestamps: false,
tableName: 'degree'
})
Degree.associate = (models) => {
Degree.belongsToMany(models.doctor, { through: 'doctor_degree', foreignKey: 'degree_id' })
};
Doctor_Degree model:
const Doctor_Degree = _sequelize.define('doctor_degree', {
doctor_id: {
type: Sequelize.STRING,
allowNull: false,
references: {
model: 'doctor',
key: 'id'
}
},
degree_id: {
type: Sequelize.STRING,
allowNull: false,
references: {
model: 'degree',
key: 'id'
}
}
},{
timestamps: false,
tableName: 'doctor_degree'
});
And I have a service to find all doctor with degree
var result;
try{
await doctorModel.findAll({
attributes: ['id','fullname', 'email','gender','address','phone','avatarurl','active','license'],
include: [{
model: degreeModel,
as: 'degree'
}]
}).then((doctors) => {
result = doctors
})
}
catch(err){
throw err
}
return result
But i got the following error:
[SequelizeEagerLoadingError]: degree is not associated to doctor!
Can anyone suggest what I am doing wrong?

findall many to many sequelize

I have a list of many to many of the people tables and lists. I need to make a query that includes the relation table, something like:
SELECT p.id, pl.id
FROM people p inner join peopletolists pl
WHERE p.id == pl.id
My models:
Lists model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const lists = sequelize.define('lists', {
listId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
nome: DataTypes.STRING(50),
status: DataTypes.STRING(1),
parametros: DataTypes.STRING(500)
}, {
timestamps: false,
});
lists.associate = function(models) {
lists.belongsToMany(models.people, {
through: models.peopletolists,
foreignKey: 'listId',
});
}
return lists;
};
People model:
'use strict';
module.exports = (sequelize, DataTypes) => {
const people = sequelize.define('people', {
peopleId: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
cpf: DataTypes.STRING(11),
name: DataTypes.STRING(50),
city: DataTypes.STRING(50),
}, {
timestamps: false
});
people.associate = function (models) {
people.belongsToMany(models.lists, {
through: models.peopletolists,
foreignKey: 'peopleId'
});
}
return people;
};
N:M model:
'use strict';
module.exports = function (sequelize, DataTypes) {
const peopletolists = sequelize.define("peopletolists", {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true,
unique: true,
},
listId: {
type: DataTypes.INTEGER,
references: {
model: 'lists',
key: 'listId'
},
allowNull: false
},
peopleId: {
type: DataTypes.INTEGER,
references: {
model: 'people',
key: 'peopleId'
},
allowNull: false
}
}, {
timestamps: false
});
return peopletolists;
}
Query:
router.get('/', function (req, res, next) {
model.lists.findAll({
include: [{
model: model.peopletolists,
}]
})
.then(lists => res.json({
data: lists,
}))
.catch(err => res.json({
error: err,
}))
});
Error: SequelizeEagerLoadingError
A person has many lists and lists have many people. I have not found many things in the Sequelize documentation and not many people complaining about this error, it's generally on ClassMethods, but I'm not even using it.
What's wrong?
This is how I am using it.
ArtistModel.findAll({
where: {
slug: req.params.slug
}, attributes: ['id']
, include: [{
model: Genres,
as: 'ArtistGenre',
required: false,
// attributes: ['id'],
through: {attributes: []},
}],
subQuery: false,
limit: req.query.limit,
offset: req.skip
})
Where Genre is the table that is linked with the Artist table with a many-to-many relationship through ArtistGenre
ArtistGenre Model:
const db = require('../utils/connection');
const Sequelize = require('sequelize');
let ArtistGenre = db.define('artist_genre', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
}
}, {
timestamps: false,
underscored: true
});
ArtistGenre.removeAttribute('id');
module.exports = ArtistGenre;
Artist:
const db = require('../utils/connection');
const Sequelize = require('sequelize');
module.exports = db.define('artist', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
},
status: {
type: Sequelize.ENUM,
values: ['active', 'inactive'],
defaultValue: 'active'
},
created_at: {
type: 'TIMESTAMP',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false
},
updated_at: {
type: 'TIMESTAMP',
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
allowNull: false
}
}, {
underscored: true,
timestamps: false
});
Genre Model:
const db = require('../utils/connection');
const Sequelize = require('sequelize');
module.exports = db.define('genre', {
id: {
type: Sequelize.BIGINT(20),
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
}
}, {
timestamps: false
});
Associations are like the following:
Artist.belongsToMany(models.genre, {as: 'ArtistGenre', through: 'artist_genre', foreignKey: 'artist_id', otherKey: 'genre_id'});
Genre.belongsToMany(models.artist, {as: 'ArtistGenre', through: 'artist_genre', foreignKey: 'genre_id', otherKey: 'artist_id'});

Resources