Sequelize many-to-many association - Method not found - javascript

I have two n:m sequelize models as shown below
// Organization Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
required: true
},
},
associations: function() {
Organization.belongsToMany(Contact, {
through : OrganizationContact,
foreignKey: {
name: 'organizationId',
allowNull: false
}
});
}
};
// OrganizationContact Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
}
}
}
// Contact Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
required: true
},
lastname: {
type: Sequelize.STRING,
required: false
},
},
associations: function() {
Contact.belongsToMany(Organization, {
through : OrganizationContact,
foreignKey: {
name: 'contactId',
allowNull: false
}
});
}
};
I am trying to insert a contact and attach it to an existing organization. My data looks like
{
"firstname" : "Mathew",
"lastname" : "Brown",
"organizationId" : 1 // Add the contact to an existing organization. I am missing something here.
}
Note : There can be multiple contacts attached to multiple organizations. An organization is created before a contact.
Based on this documentation, after saving the contact when I tried
Organization.addContact(contact);
I get an exception saying
Organization.addContact is not a function

The addContact method should be called on instance of Organization rather than on the model itself, just as you do in the example code.
Organization.create(organizationData).then(organization => {
organization.addContact(contact).then(() => {
// contact was added to previously created organization
});
});
You do not need the organizationId attribute in your contact create data. If you want to add new contact to the organization with id: 1, then you first need to return the organization instance and then perform the addContact method
Organization.findByPrimary(1).then(organization => {
organization.addContact(contact).then(() => {
// contact was added to organization with id = 1
});
});

Related

Sequelize: Foreign key declared, but does not appear in the table

I'm new to using Sequelize and for that I strictly follow the documentation here. It is written that we must use hasOne(), hasMany(), belongsTo() in order to add automatically the foreign keys. In my situation: I have a Category and a FAQ model, defined so:
Category.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Category = sequelize.define('Category', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
categoryShop_id: {
type: Sequelize.DataTypes.UUID,
allowNull: true
},
name: {
type: Sequelize.DataTypes.STRING,
allowNull: false
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
parent_id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: true
}
});
Category.associate = (models) => {
Category.hasMany(models.faqs, {
onDelete:'CASCADE',
onUpdate:'CASCADE'
});
};
module.exports = Category;
Faq.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Faq = sequelize.define('Faq', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
question: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
answer: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
product_id: {
type: Sequelize.DataTypes.STRING,
allowNull: true
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
});
Faq.associate = (models) => {
Faq.belongsTo(models.categories, {
foreignKey: {
name: 'category_id',
allowNull: true
}
});
};
module.exports = Faq;
The migrations run without any errors, but I don't see the added columns to the table. What is the reason for this?
Your confusing model and migration code. Your migrations are ok, but lack the right foreign key columns for your associations.
Your association code looks ok but it belongs in your model.
Look at https://sequelizeui.app/ for some example code.

How to add sequelize association?

So i have two models - One is User and other is Wallet. Now, the association is - user hasOne Wallet !
Am using sequelize cli to create model and migration, so when i created a new model named Wallet - it generated a model & migration file, Now how to add association ? Should i need to add both hasOne and belongs to ?
This is my migration file of Wallet :
await queryInterface.createTable('Wallets', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
references: { model: 'users', key: 'id' },
onDelete: 'CASCADE',
},
balance: {
type: Sequelize.STRING
},
userType: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
I have manually added userId, ( is this needs to be manually added or it will be automatically created when sync ? )
This is my User Model code:
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(models) {
}
};
User.init({
name: DataTypes.STRING,
email: {
type: DataTypes.STRING,
validate: {
isEmail: true
}
},
phone: {
type: DataTypes.STRING,
unique: true
},
}, {
sequelize,
modelName: 'User',
});
In this code, there is static associate(models) { } How to add association to this ? Or how actually association needs to be done between user and Wallet ?

SequelizeJS HasOne association error

I am relatively new to NodeJS and SequelizeJS and am facing a hasOne issue with a query I am building and I'd like to know your thoughts about this issue to find out where I gone wrong and the correct way to implement this query.
Association Here
The models where generated using sequelize-auto (pg-hstore).
Bloco Model:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('bloco_condominio', {
id_bloco: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
id_condominio: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'condominio',
key: 'id_condominio'
}
},
nm_bloco: {
type: DataTypes.STRING,
allowNull: true
},
ic_status: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: "A"
}
}, {
tableName: 'bloco_condominio'
});
};
Apartamento Model:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('apartamento', {
id_apartamento: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
id_condominio: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'condominio',
key: 'id_condominio'
}
},
nu_apto: {
type: DataTypes.STRING,
allowNull: true
},
id_bloco: {
type: DataTypes.INTEGER,
allowNull: true,
references: {
model: 'bloco_condominio',
key: 'id_bloco'
}
},
ic_status: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: "A"
},
dt_incl: {
type: DataTypes.TIME,
allowNull: false,
defaultValue: sequelize.fn('now')
},
dt_ult_alt: {
type: DataTypes.TIME,
allowNull: false,
defaultValue: sequelize.fn('now')
}
}, {
tableName: 'apartamento'
});
};
Apartamento Service:
"use strict";
var model = require('../models');
var Utils = require('../utils/utils');
var service = {};
var Apartamento = model.apartamento;
var Bloco = model.bloco_condominio;
var Morador = model.morador;
var Pessoa = model.pessoa;
//Incluir relação OneToMany
Apartamento.hasMany(Morador, { as: "Moradores", foreignKey: 'id_apartamento' });
Morador.belongsTo(Apartamento, { foreignKey: 'id_apartamento' });
Morador.hasMany(Pessoa, { as: "Pessoa", foreignKey: 'id_pessoa' });
Pessoa.belongsTo(Morador, { foreignKey: 'id_pessoa' });
Bloco.hasMany(Apartamento, { as: "Bloco", foreignKey: 'id_bloco' });
Apartamento.hasMany(Bloco, { foreignKey: 'id_bloco' });
service.getApartamentoById = function(idApartamento) {
return Apartamento.findById(idApartamento, {
include: [
{ model: Morador, as: 'Moradores', include: [
{ model: Pessoa, as: 'Pessoa'}
]},
{ model: Bloco, as: 'Bloco' }
]
})
.then(function(data) {
return data;
})
.catch(function(err) {
throw 'Erro ao consultar apartamento por ID: ' + err.message + ' - Request: '+JSON.stringify(idApartamento);
});
};
I can perfectly retrieve the other hasMany associations, but still hasn't found a way to do so in the reverse way.
Do you guys have any idea of how I should approach this issue in the correct manner?
Thanks in advance for your help!
Best regards,
Enrico Bergamo
To make it simpler for me (only knowing English), I've grabbed the following from Google translate:
Pessoa: Person
Morador: Dweller
Bloco: Block
Apartmento: Apartment
So, Dweller can have many People, an Apartment can have many Dwellers and a Block can have many Apartments.
Your definition on the other models indicates they're all 1:m, so I followed that assumption for Apartments and Blocks.
With that in mind, the following should work.
Bloco.hasMany(Apartamento, { as: "Apartmento", foreignKey: 'id_bloco' });
Apartamento.belongsTo(Bloco, { foreignKey: 'id_bloco' });
Note: I've changed the as: "Bloco" to as: "Apartmento" and the second hasMany to belongsTo. This might be where your issues were coming from.
Edit: The method to access the Apartments that belong to a Block is:
bloco.getApartmento(options)
I have this working with this promise chain:
Bloco.create()
.then(block => {
return Promise.all([
block,
Apartamento.bulkCreate([{
id_bloco: block.id_bloco
}, {
id_bloco: block.id_bloco
}, {
id_bloco: block.id_bloco
}, {
id_bloco: block.id_bloco
}, {}])
])
})
.spread((bloco, apartment) => {
return bloco.getApartamento()
})
.then(apartments => {
console.log(apartments.length); --> Logs 4 which matches the bulk create.
})
If I've misinterpreted, and it should be an n:m relationship (Apartments/Blocks), then you should use belongsToMany on each model and identify the through option.
Bloco.belongsToMany(Apartamento, {
as: "Apartmentos",
foreignKey: 'id_bloco',
through: "BlocoAparmento"
});
Apartamento.belongsToMany(Bloco, {
as: "Blocos",
foreignKey: 'id_apartmento',
through: "BlocoAparmento"
});
This will create an n:m joining table called "BlockApartmento". If you define that model, and use the model instead of the string, you'll have complete control over the models settings.
This will give you the Bloco.getApartmentos( methods as well as opposite (Apartmento.getBlocos() along with setAssociation, addAssoc... etc
http://docs.sequelizejs.com/manual/tutorial/associations.html#belongs-to-many-associations

How to query on shared ids tables on sequelize

I have 4 tables/models that shares ids as primary keys, but for the example I will just show 2
User: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false
}
Person: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false
},
name: {
type: Sequelize.STRING
}
I am using shared ids, so the person primary key is the primary key of User, it doesn't have autoimcrement. So is there a way to make a join between those 2 tables? I've tried to do something like:
getAll(){
return User.getAll({
include: [{
model:Person,
}]
})
}
But since there is no relation it doesn't work. What should I do?
Thanks
You cannot use include without a relationship. You could use a raw query to retrieve the information like:
var queryString = 'select * from User u join Person p on u.id = p.id where u.id = :sharedId';
models.sequelize
.query(queryString, {
replacements: { shareId: id},
type: models.sequelize.QueryTypes.SELECT
})
.then(function(result) {
res.json(attendance);
});
But then you would have to implement validations to make sure tables are filled up correclty.
However I would encourage you to implement relationships between your tables as It would be more maintainable. Something like this:
var User = sequelize.define("User", {
id: { type: DataTypes.INTEGER, primaryKey: true},
name: { type: DataTypes.STRING, name: 'name' },
...
}, {
classMethods: {
associate: function(models) {
User.hasOne(models.Person);
}
}
});
var Person = sequelize.define("Person", {
id: { type: DataTypes.INTEGER, primaryKey: true},
name: { type: DataTypes.STRING, name: 'name' },
...
}, {
classMethods: {
associate: function(models) {
Person.belogsTo(models.User);
}
}
});

How to create a list of objects which are one-way associated with objects of another model in SailsJS?

I have models Playlist.js and User.js. I want to have a list of users in Playlist who can answer for the comments on them. I do not want the attribute to appear in User. (i.e. one-way-association)
Playlist.js
module.exports = {
attributes: {
id: {
type: 'integer',
autoIncrement: true,
primaryKey:
},
name: {
type: 'string',
size: 128,
required: true
},
// many to many relationship with role
roles_with_access: {
collection: 'role',
via: 'playlist',
through: 'rolehasplaylist'
},
// THIS ATTRIBUTE ASSOCIATE WITH ONE USER
// BUT INSTEAD OF THAT I WANT A LIST OF USERS
users_who_can_answer_comments: {
model: 'user'
}
}
};
User.js
module.exports = {
attributes: {
id: {
type: 'integer',
autoIncrement: true,
primaryKey: true,
},
name: {
type: 'string',
size: 128,
required: true
},
email: {
type: 'email',
required: true,
unique: true
},
adminRole: {
model: 'role'
}
}
};
Sails documentation have mentioned one-way association only for one-to-one mapping - http://sailsjs.org/documentation/concepts/models-and-orm/associations/one-way-association
I want to find a way to have a list of users with associations to users?
Change model to collection:
users_who_can_answer_comments: {
collection: 'user'
}

Categories