sequelize querying by association - nested includes? - javascript

Here is my account Model:
module.exports = {
attributes: {
accountPkey: {
type: Sequelize.INTEGER,
primaryKey: true,
field: 'account_pkey'
},
accountName: {
type: Sequelize.STRING,
allowNull: false,
field: 'account_name'
},
imagePkey: {
type: Sequelize.INTEGER,
field: 'image_pkey'
}
},
associations: function() {
Account.hasMany(Privilege, {
as: 'Privileges',
foreignKey: 'account_pkey'
});
Account.hasMany(AccountContact, {
as: 'Contacts',
foreignKey: 'account_pkey'
});
},
options: {
tableName: 'v_account',
timestamps: false,
classMethods: {
whereUserIs(user_pkey, privileges) {
return Account.findAll({
include: [{
model: Privilege,
where: {
'Privilege.privilege_type_name': {
$in: privileges
},
'Privilege.user_pkey': {
$eq: user_pkey
}
}
}]
});
}
},
instanceMethods: {},
hooks: {}
}
};
In my whereUserIs class method I am trying to return all accounts for which there exists a privilege which has the user_pkey and has any of the privileges passed in.
Please assume that the Privilege model has account_type_name and user_pkey properties. Is my syntax correct?
Edit: I am actually using this sails hook to load sequelize: https://www.npmjs.com/package/sails-hook-sequelize
Second Edit:
Here is a more complicated query: I would like to find all users which have a privelege on any of the accounts that were queried above:
User.findAll({
include: [
{
model: Privilege,
include: [
{
model: Account,
include: [{
model: Privelege,
where: {
'Privilege.privilege_type_name': {
$in: privileges
},
'Privilege.user_pkey': {
$eq: user_pkey
}
}
}]
}
]
}
]
})
Does this second one make sense?
In both of these queries, will I get a list of entities (i.e. accounts or users) or will they be nested results (of all the includes)? How can I ensure that my lists of accounts and users are unique/distinct?

Related

how to relational data one-to-one and many-to-many in sequalize in model same?

I have a problem in findById data with relational sequelize.
Where I have the condition of the One-to-One and Many-to-Many relations
TB_User is related on-to-one with tb_corporate
TB_User is related to many-to-many with TB Corporate and this data relations are saved in TB_corporate_Group
My problem, when I want to get corporate and corporate group. The data I get is data from the user table where the relationship is one-to-one.
this is code in model users
module.exports = (sequelize :any ) => {
class users extends Model{
static associate(models : any) {
// define association here
users.belongsToMany(models.corporate, {
through: 'corporateGroup',
as: 'dataCorporateGroup'
})
users.hasOne(models.corporate, {foreignKey: 'userId', as: 'corporate'})
}
}
users.init({
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
field: 'name',
type: DataTypes.STRING,
allowNull: false,
},
}, {
sequelize,
modelName: 'users',
});
return users;
};
code for model corporate
module.exports = (sequelize :any ) => {
class corporate extends Model{
static associate(models : any) {
// define association here
corporate.belongsTo(models.users, {foreignKey: 'userId', as: 'userCorporate'})
corporate.belongsToMany(models.users, {
through: 'corporateGroup',
as: 'userCorporate'
})
}
}
corporate.init({
userId: {
field: 'user_id',
type: DataTypes.INTEGER,
allowNull: false,
unique: true,
},
corporateName: {
field: 'name',
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
}, {
sequelize,
modelName: 'corporate',
});
return corporate;
};
code for model corporate group
module.exports = (sequelize :any ) => {
class corporateGroup extends Model{
static associate(models : any) {
// define association here
}
}
corporateGroup.init({
corporateId: {
field: 'corporate_id',
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'corporate',
key: 'id'
}
},
userId: {
field: 'user_id',
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'users',
key: 'id'
}
}
}, {
sequelize,
tableName: 'corporate_group',
modelName: 'corporateGroup',
});
return corporateGroup;
};
and this code for find by id
await corporate.findById(id, {
include: [{
model: db.users,
as: 'userCorporate',
}]
})
You need to indicate the unique aliases for associations
corporate.belongsTo(models.users, {foreignKey: 'userId', as: 'userCorporate'})
corporate.belongsToMany(models.users, {
through: 'corporateGroup',
as: 'corporateGroupUsers'
})
and then you can indicate included models with these aliases to get both of them along with corporate record:
await corporate.findById(id, {
include: [{
model: db.users,
as: 'userCorporate',
}, {
model: db.users,
as: 'corporateGroupUsers',
}]
})

Empty Array when use random with Sequelize

I'm working on an API in Node.js with the Sequelize ORM.
I make an API route to retrieve a random question, it works one time out of three but often returns an empty array. I can't find a solution in the documentation to prevent this...
app.get('/:certifName/:levelName/random', async function (req, res) {
return await Certification.findOne(
{
attributes: ['id', 'label'],
include: [{
model: CertificationLevel,
as: "tcl",
required: true,
attributes: ['id', 'label', 'question_number', 'exam_duration'],
include: [{
attributes: ['id', 'label'],
model: CertificationChapter,
as: "tcc",
required: true,
limit: 1,
order: [ [ Sequelize.fn('RANDOM') ] ],
include: [{
model: Question,
as: "tq",
required: true,
include: [{
model: QuestionChoice,
as: "tqc",
required: false,
attributes: ['id', 'label_fr', 'is_answer'],
}],
}],
}],
where: { label: req.params.levelName }
}],
where: { label: req.params.certifName }
})
.then(data => {
if (data) {
res.send(data);
}
else
res.sendStatus(204);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Error retrieving certification details"
});
});
});
The last model :
module.exports =
class CertificationLevel extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
label: Sequelize.STRING,
slug: Sequelize.STRING,
description: Sequelize.TEXT,
question_number: Sequelize.INTEGER,
exam_duration: Sequelize.INTEGER,
created_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
updated_at: Sequelize.DATE,
deleted_at: Sequelize.DATE
},
{
tableName: 't_certifications_levels',
sequelize,
underscored: true,
timestamps: false
},
);
}
static associate(models) {
this.belongsTo(models.Certification, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false,
name: "certification_id"
}
}),
this.hasMany(models.CertificationChapter, { as:'tcc', foreignKey: 'level_id' })
this.hasMany(models.Subscription, { as:'ts',foreignKey: 'level_id' })
}
}
And this is a SQL query generate :
SELECT "Certification".*,
"tcl"."id" AS "tcl.id",
"tcl"."label" AS "tcl.label",
"tcl"."question_number" AS "tcl.question_number",
"tcl"."exam_duration" AS "tcl.exam_duration"
FROM
(SELECT "Certification"."id",
"Certification"."label"
FROM "t_certifications" AS "Certification"
WHERE "Certification"."label" = 'ISTQB'
AND
(SELECT "tcl"."certification_id"
FROM "t_certifications_levels" AS "tcl"
WHERE ("tcl"."label" = 'Fondation'
AND "tcl"."certification_id" = "Certification"."id")
LIMIT 1) IS NOT NULL
LIMIT 1) AS "Certification"
INNER JOIN "t_certifications_levels" AS "tcl" ON "Certification"."id" = "tcl"."certification_id"
AND "tcl"."label" = 'Fondation';
I don't know why I have two executing to my route?
I am a real beginner in back development...
Thank for you help

Nodejs use JOIN for two tables on sequelize

I'm trying to implementing this mysql command on sequelize, but as far as i'm newbie to use this library i can't implementing that
i want to make this sql command:
SELECT * FROM users
join users_contacts_lists on users_contacts_lists.mobile_number = users.mobile_number
WHERE users_contacts_lists.user_id = 1
My models to create database schema:
'use strict';
var config = require('../config');
var User = config.sequelize.define('users', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
password: {
type: config.Sequelize.STRING
},
username: {
type: config.Sequelize.STRING
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number'
},
status: {
type: config.Sequelize.STRING
},
}, {freezeTableName: true});
var UsersContactsLists = config.sequelize.define('users_contacts_lists', {
id: {
type: config.Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true
},
userId: {
type: config.Sequelize.INTEGER,
field: 'user_id'
},
mobileNumber: {
type: config.Sequelize.STRING,
field: 'mobile_number', defaultValue: 0
}
}, {freezeTableName: true});
UsersContactsLists.belongsTo(ChannelsTypes, {foreignKey: 'user_id'});
User.hasMany(Channels, {foreignKey: 'id'});
User.sync();
UsersContactsLists.sync();
module.exports =
{
users: User,
usersContactsLists: UsersContactsLists
};
how can i resolve this problem? Thanks in advance
You can define the target key and the foreign key both in a relation like this:
User.belongsTo(UsersContactsLists, {targetKey:'mobileNumber',foreignKey: 'mobileNumber'});
And then you can use this:
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]
})
Fiddled around a bit, does this statement do what you want?
User.findAll({
include: [{
model: UsersContactsLists,
where: {
userId: 1
}
}]

How to query many to many relationship sequelize?

Tables have many to many relationship, junction by an order table in between.
Outlet --> Order <-- Product
I want to get the list of Outlet for today Order.
So here is a function to get all outlets:
db.Outlet.findAll({include: [
{model:db.Product, attributes: ['id', 'name', 'nameKh']}
]}).then(function(outlets){
return res.jsonp(outlets);
})
I got this result:
I can only select with where Product Id by using this:
db.Outlet.findAll({include: [
{model:db.Product, attributes: ['id', 'name', 'nameKh'], where: {id: 2}
]}).then(function(outlets){
return res.jsonp(outlets);
})
How can I query by specific order amount, or today order date?
Here are my models:
Outlet:
var Outlet = sequelize.define('Outlet', {
outletCode: DataTypes.STRING,
outletName: DataTypes.STRING,
outletNameKh: DataTypes.STRING,
outletSubtype: DataTypes.STRING,
perfectStoreType: DataTypes.STRING,
address: DataTypes.STRING
},
{
associate: function(models){
Outlet.belongsToMany(models.Product, {through: models.Order});
Outlet.belongsTo(models.Distributor);
// Outlet.hasMany(models.Order);
}
}
);
Product:
var Product = sequelize.define('Product', {
inventoryCode: DataTypes.STRING,
name: DataTypes.STRING,
nameKh: DataTypes.STRING,
monthlyCaseTarget: DataTypes.INTEGER,
pieces: DataTypes.INTEGER,
star: DataTypes.BOOLEAN,
price: DataTypes.FLOAT,
active: DataTypes.BOOLEAN
},
{
associate: function(models){
Product.belongsToMany(models.Outlet, {through: models.Order});
Product.belongsTo(models.Category);
// Product.hasMany(models.Order);
}
}
);
Order:
var Order = sequelize.define('Order', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
amount: DataTypes.INTEGER
},
{
associate: function(models){
Order.belongsTo(models.Outlet);
Order.belongsTo(models.Product);
Order.belongsTo(models.User);
}
}
);
Try it:
db.Outlet.findAll({
include: [{
model:db.Product,
attributes: ['id', 'name', 'nameKh'],
through: { where: { amount: 10 } }
}]
})
Similar case
Super many to many relatioship
User.belongsToMany(Profile, { through: Grant });
Profile.belongsToMany(User, { through: Grant });
User.hasMany(Grant);
Grant.belongsTo(User);
Profile.hasMany(Grant);
Grant.belongsTo(Profile);
This way, we can do all kinds of eager loading:
// All these work:
User.findAll({ include: Profile });
Profile.findAll({ include: User });
User.findAll({ include: Grant });
Profile.findAll({ include: Grant });
Grant.findAll({ include: User });
Grant.findAll({ include: Profile });
We can even perform all kinds of deeply nested includes:
User.findAll({
include: [
{
model: Grant,
include: [User, Profile]
},
{
model: Profile,
include: {
model: User,
include: {
model: Grant,
include: [User, Profile]
}
}
}
]
});
From sequelize doc

Sequelize.js insert a model with one-to-many relationship

I have two sequelize models with one-to-many relationship. Let's call them Owner and Property.
Assume they are defined using the sails-hook-sequelize as such (simplified).
//Owner.js
module.exports = {
options: {
tableName: 'owner'
},
attributes: {
id: {
type: Sequelize.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING(255)
},
associations: function () {
Owner.hasMany(Property, {
foreignKey: {
name: 'owner_id'
}
});
}
}
//Property.js
module.exports = {
options: {
tableName: 'property'
},
attributes: {
id: {
type: Sequelize.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING(255)
}
}
Now assume I want to insert an Owner record in my database and insert a few property records to associate with the owner. How do I do this?
I'm looking for something like
Owner.create({name:'nice owner',
property: [{name:'nice property'},
{name:'ugly property'}]});
Surprisingly I can't find this in the Sequelize documentation.
You can't associate property existing records when you create the owner, you have to do that right after, with promise chain.
Owner.create({name:'nice owner'}).then(function(owner){
owner.setProperties([{name:'nice property'}, {name:'ugly property'}]).then(/*...*/);
});
To avoid any problems with those associations (owner created but some associations failed), it's better to use transactions.
sequelize.transaction(function(t) {
return Owner.create({name:'nice owner'}, {transaction: t}).then(function(owner){
return owner.setProperties([{name:'nice property'}, {name:'ugly property'}], {transaction : t});
});
});
However, if you want to create new Owner associated to new Properties you can do something like
Owner.create({
name: 'nice owner',
property: [
{ name: 'nice property'},
{ name: 'ugly property'}
]
},{
include: [ Property]
});
See http://docs.sequelizejs.com/en/latest/docs/associations/#creating-with-associations

Categories

Resources