Prevent SailJS waterline to create columns which are used for association - mysql

I am new to NodeJs/sailsJS.
I have following models:
Person
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
person_id: {
type: 'integer',
primaryKey: true,
autoIncrement: true
},
user: {
model: 'user'
},
person_name: {
type: 'string',
required: true,
size: 128
},
person_birthdate: {
type: 'date'
},
person_gender: {
type: 'string',
size: 1
}
}
};
User
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
user_id: {
type: 'integer',
primaryKey: true,
autoIncrement: false
},
person: {
model: 'person'
}
}
};
It creates column person in user table and column user in person table. How do I stop these columns to pop up and still be able to use waterline. Entity Framework in C# MVC is able to provide that functionality, so I think there might be a way to do it in SailsJs.

Try to add in file config/models.js this line: migrate: 'safe' to exported configuration.
About model settings you can read here: sailsjs.org/documentation

Related

Sequelize M:N association not updating through table record

When I try to update a recipe with associated tags using the through option, no record is updated in the joining table in the mysql database I'm connected to.
Here are my models definitions:
export const Recipe = sequelize.define('Recipe', {
// Model attributes are defined here
title: {
type: DataTypes.STRING,
allowNull: false
},
image: {
type: DataTypes.STRING,
allowNull: true
},
prepTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
cookTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
totalTime: {
type: DataTypes.DOUBLE,
allowNull: false
},
servings: {
type: DataTypes.INTEGER,
allowNull: false
},
rating: {
type: DataTypes.INTEGER,
allowNull: false
},
notes: {
type: DataTypes.STRING, allowNull: true
},
}, {
// Other model options go here
tableName: 'Recipes'
});
export const Tag = sequelize.define('Tag', {
// Model attributes are defined here
name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
// Other model options go here
tableName: 'Tags'
});
export const RecipeTag = sequelize.define('RecipeTag', {
// Model attributes are defined here
}, {
// Other model options go here
timestamps: false,
tableName: 'RecipeTags'
});
Here are my associations:
Recipe.belongsToMany(Tag, {
through: RecipeTag,
foreignKey: 'recipeId',
as: 'tags'
})
Tag.belongsToMany(Recipe, {
through: RecipeTag,
foreignKey: 'tagId',
as: 'recipes'
})
Here is the update call:
Recipe.update(args, {
include: [{
model: Tag,
through: RecipeTag,
as: 'tags',
where: {
recipeId: args.id
}
}],
where: {
id: args.id
},
});
Only one update mysql call is executed on the Recipes table. Is it possible to update the RecipeTags through table record in the same update call?

I created oneToMany relation but how I can get the single record belongs to the many record in Sequalize

Tagcategories Model
export const TagCategories = sequelize.define(
"tag_categories",
{
categoryId: {
type: DataTypes.INTEGER,
field: "category_id",
autoIncrement: true,
primaryKey: true,
},
title: {
type: DataTypes.STRING(50),
field: "title",
allowNull: false,
unique: true,
},
},
);
TagCategories.hasMany(TagGroups, {
foreignKey: "categoryId",
sourceKey: "categoryId",
});
export default TagCategories;
TagGroups Model
export const TagGroups = sequelize.define(
"tag_groups",
{
tagGroupId: {
type: DataTypes.INTEGER,
field: "tag_group_id",
autoIncrement: true,
primaryKey: true,
},
categoryId: {
type: DataTypes.INTEGER,
field: "category_id",
allowNull: false,
},
title: {
type: DataTypes.STRING(50),
field: "title",
allowNull: false,
unique: true,
},
},
);
In the above models I establish oneToMany relationship between the TagCategories and TagGroups
But I want to fetch the record from the TagGroup table with the TagCategories details.
Thanks in advance
Did you look at examples in official documentation?
Also, you need to add an association from TagGroups to TagCategories:
// there is no need to indicate `sourceKey` if this field is a primary key
TagGroups.belongsTo(TagCategories, {
foreignKey: "categoryId",
});
It's better to define all associations in static functions and call all of them separately after all models will be registered.
See the question and my answer here how to do it
In your case, the final request would be something like this
const tagGroup = await TagGroups.findOne({
where: {
tagGroupId: groupId
},
include: [{
model: TagCategories
}]
})

Node.js Sequelize virtual column pulling value from other model

I'm working with Sequelize 5.7, trying to utilize virtual datatype,
to pull related information into a model.
Given simplified company and user models, how do I get company.name
into user.companyname ?
company
let Schema = sequelize.define(
"company",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING(45)
}
}
);
user
let Schema = sequelize.define(
"user",
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company: {
type: DataTypes.INTEGER.UNSIGNED,
references: {
model: sequelize.model('company'),
key: 'id'
}
},
/* This companyname contruct is pure fantasy, and the target of my question */
companyname: {
type: new DataTypes.VIRTUAL(DataTypes.STRING,['company']),
references: {
model: 'company',
key: 'name'
}
}
}
);
In your case, I think it is a better idea to use a relationship (an association)
Sequelize Associations
const User = sequelize.define('user', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
});
const Company = sequelize.define('company', {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
});
User.belongsTo(Company, {
foreignKey: 'company_id', // you can use this to customize the fk, default would be like companyId
});
Company.hasMany(User);
Then when calling your model you do something like:
User.findAll({ include: Company }).then(users => console.log(users));
I solved the problem by using type: DataTypes.VIRTUAL in model
const { Model, DataTypes } = require('sequelize');
class User extends Model {
static init(sequelize) {
super.init({
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true
},
login: {
type: DataTypes.STRING(45),
unique: true
},
company_id: {
type: DataTypes.INTEGER.UNSIGNED,
},
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `companyname` value!');
}
},
}, {
sequelize
})
}
static associate(models) {
this.belongsTo(Company, {
foreignKey: 'company_id',
});
}
}
module.exports = User;
to search just include the association :
User.findAll({ include: Company })
I usually create each model using 'class' in different files, but if you need, just include the code below in the #jalex19 solution
companyname:{
type: DataTypes.VIRTUAL,
get() {
return this.Company?.get().name;
},
set(/*value*/) {
throw new Error('Do not try to set the `fullName` value!');
}
},

Dynamic define database in Sequelize for multi-tenant support return wrong query syntax

I'm Working on Multi-tenant Application (SAAS) with Shared Database Isolated Schema principle.
I've tried solution from https://github.com/renatoargh/data-isolation-example
from this article https://renatoargh.wordpress.com/2018/01/10/logical-data-isolation-for-multi-tenant-architecture-using-node-express-and-sequelize/
This is My Sequelize Model using schema Option
module.exports = (sequelize, DataTypes) => {
const Task = sequelize.define('Task', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
field: 'Id'
},
description: {
type: DataTypes.STRING(100),
allowNull: false,
field: 'Description'
},
done: {
type: DataTypes.BOOLEAN,
allowNull: false,
default: false,
field: 'Done'
},
taskTypeId: {
type: DataTypes.INTEGER,
allowNull: true,
field: 'TaskTypeId'
},
userId: {
type: DataTypes.INTEGER,
allowNull: true,
field: 'UserId'
}
}, {
freezeTableName: true,
tableName: 'Tasks',
createdAt: false,
updatedAt: false
})
Task.changeSchema = schema => Task.schema(schema)
Task.associate = models => {
Task.belongsTo(models.TaskType, {
as: 'taskType',
foreignKey: 'taskTypeId'
})
}
return Task
}
And Stop at this problem
SELECT
`Task`.`Id` AS `id`,
`Task`.`Description` AS `description`,
`Task`.`Done` AS `done`,
`Task`.`TaskTypeId` AS `taskTypeId`,
`Task`.`UserId` AS `userId`,
`taskType`.`Id` AS `taskType.id`,
`taskType`.`Description` AS `taskType.description`
FROM `tenant_1.Tasks` AS `Task` LEFT OUTER JOIN `shared.TaskTypes` AS `taskType`
ON `Task`.`TaskTypeId` = `taskType`.`Id`
WHERE `Task`.`UserId` = 1;
as you see, FROM `tenant_1.Tasks` in mysql is a wrong syntax. it must be FROM `tenant_1`.`Tasks`
how to change `tenant_1.Tasks` to `tenant_1`.`Tasks`
Are you using MySQL? If so, that is the expected behavior.
From the documentation of Model.schema:
Apply a schema to this model. For postgres, this will actually place the schema in front of the table name - "schema"."tableName", while the schema will be prepended to the table name for mysql and sqlite - 'schema.tablename'.

Sequelize 4 - belongs-To-Many insert issue on eagger loading

Hi Folks, I have these two models:
const media = sequelize.define('media', {
id: { type: Sequelize.UUID, primaryKey: true, defaultValue: Sequelize.UUIDV4 },
name: { type: Sequelize.STRING, allowNull: false, unique:'compositeIndex' },}, { freezeTableName: true });
const mediaGenre = sequelize.define('mediaGenre', {
id: { type: Sequelize.UUID, primaryKey: true, defaultValue: Sequelize.UUIDV4 }}, { freezeTableName: true, name: { plural: 'mediaGenre' } });
and these two relations:
media.hasMany(mediaGenre, as: 'mGenre');
mediaGenre.belongsTo(media);
media.belongsToMany(genre, { through: mediaGenre });
genre.belongsToMany(media, { through: mediaGenre });
when I want to create a media I do:
MediaModels.media.create(
{name: 'Hulk',
mediaGenre: [
{ genreId: '021baab5-7fc6-4b06-aca5-e4b1ed1f3ce4' },
{ genreId: '03f069a4-dc52-4ab5-82d3-6bcd67d2d29e' }]},
{
include: [
{model: MediaModels.mediaGenre, as: 'mGenre'}
]
}
);
These has been working with sequelize 3 and recently I updated to sequelize 4.4.2 and it is not throwing error but the table mediaGenre it's not been populated.
Any ideas of what could be the error?
Have you tried to sync after you referenced the association? I had this issue and when i called to sync (with force false, this is important if tou dont want to erase your schema and to be recreated), the junction table was created.
If you are using sequelize-cli,also notice that in this version, classMethods are not longer supported. Instead, you shold add a method called associate directly to your model, which will be called in your models/index.js.