I'm using MariaDB v10.2.11, and since v10.2.7 you can have JSON columns with a constraint that validates the JSON value of a row.
I want to add a that constraint through a Sequelize migration, but I don't know how to.
MariaDB JSON Documentation:
https://mariadb.com/resources/blog/json-mariadb-102
https://mariadb.com/kb/en/library/json-data-type/
I'm sharing the solution I came in this issue (https://github.com/sequelize/sequelize/issues/8767) (it's mine).
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface
.createTable('tableName', {
// id, other columns
column1: Sequelize.JSON,
// more columns
})
.then(() =>
queryInterface.addConstraint('tableName', ['column1'], {
type: 'check',
where: {
column1: Sequelize.literal('JSON_VALID(column1)'),
},
name: 'check_column1_has_valid_json',
}),
),
down: (queryInterface) => queryInterface.dropTable('tableName'),
};
Since createTable and addConstraint returns a promise, it's possible to chain multiple operations in one migration :)
Related
I'm working on a project that has some users and roles. I want to add association (belongsToMany) on users and roles. I'm using MySQL database and users are stored in users table. Currently i'm storing roles in database as well but i want roles to be stored in a file instead of database. Is there a way i could use a const instead of table from database.
index.js file:
...
db.user = require("./user.model.js")(sequelize, Sequelize);
db.role = require("./role.model.js")(sequelize, Sequelize);
db.role.belongsToMany(db.user, {
through: "user_roles",
foreignKey: "roleId",
otherKey: "userId"
});
db.user.belongsToMany(db.role, {
through: "user_roles",
foreignKey: "userId",
otherKey: "roleId"
});
role.model.js file
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define("role", {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
};
One thing that you could do is eliminate the Role table, and just create a UserRole table with a belongsTo() association to the User table. (And associate User to it by using hasMany())
You could then make the "name" column in UserRole have the ENUM datatype, and have the model draw the values available in that ENUM from reading the file in the file system. (Alternately, you can hard-code the values into the ENUM and that would be the "file" where you're updating possible role names)
I'm not totally sure what problem this is looking to solve, though. This seems like it would lead to a decrease in performance overall, though it WOULD eliminate the need for a Many-to-Many relationship that can be frustrating to work with.
I try to make a reference between two database schemes. The first scheme is clinicdatabase and the second is supportdatabase
this is the model which is creating the error:
Unhandled rejection SequelizeDatabaseError: Failed to open the referenced table 'supportdatabase.clinics'
My model Staff (scheme: clinicdatabase), which needs the id, as a foreign key, from the model Clinic (scheme: supportdatabase) looks like:
module.exports = (sequelize, DataTypes) => {
const Staff = sequelize.define("Staff", {
STAFF_PASSWORD: DataTypes.STRING,
CLI_CLINICID: {
type: DataTypes.INTEGER,
references: {
model: {
tableName: "clinics",
schema: "clinicdatabase"
},
key: 'id'
}
}
},
);
return Staff;
}
Both schemes are connected and they are working. Is these reference even possible? Do i need some permissions for the schemes? If yes do you know wher to add this or what the right syntax is?
I am using Sequelize, a nodejs ORM for mysql. Using mysql workbench I made an EEM diagram and pushed that design into the db, so far so good.
Now in Sequelize I have to tell it what the design of the DB looks like, part of that is telling it what foreign keys are called.
In Workbench there is a foreign key tab in the tablethere are variables formatted likefd_positions_tradingPLan1` but I never name that, in fact in my EEM diagram I have
Then if I go to that foreign keys tab at the bottom I get this. I am confused as to exactly what I should tell the ORM the foreign key is...
Let's take your positions Table as reference. To build your model on sequelize you have to do the following:
module.exports = (sequelize, DataTypes) => {
const Position = sequelize.define('Position', { // this is the name that you'll use on sequelize methods, not what you have on your db
// define your columns like this:
tradeName: { //the name of the variable that you'll use on sequelize and js
field: 'trade_name', //the actual name of your column on the table
type: DataTypes.STRING(128) // the data type
},
// .......
// for your foreignKeys you have to define the column like your other attributes.
userId: {
field: 'user_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'positions', //this is the name of your table on the database
underscored: true, // to recognize the underscore names
createdAt: 'created_at', //
updatedAt: 'updated_at',
});
//now for your association let's say that you defined your USER table like this example.
Position.associate = (models) => {
// on the foreignKey value, youhave to put the same that you define above, and on the db.
Position.belongsTo(models.User, { as: 'User', foreignKey: 'user_id' });
//depending on your other relations, you are gonna use hasMany, hasOne, belongsToMany
};
return Position;
};
Sequelize does the association only one way, that means that on this example, you can't query with sequelize from User to Position, to be able to
have two way association you have to defined on both models.
User.associate = (models) => {
// on this case we use hasMany cause user can have many positions I suppose, if not, use hasOne
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' }); //remeber to use the same foreignKey name
};
UPDATE:
as is an identfier for Sequelize. Let's say you make two associations for the same model, later when you try to query one of this associations, you can specify the association that you want
User.associate = (models) => {
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' });
User.hasMany(models.Poisition, { as: 'customerPositions', foreignKey: 'customer_id' });
};
//the actual association call
User.findAll({
include:[{
model: db.user,
as: 'positions'
}, {
model: db.user,
as: 'customerPositions'
}]
})
Now for fk_positions_users1, this is an identifier for MySQL itself. Sequelize only check for the foreignKey and the models involve. Obviously when Sequelize create the reference, it gives a template name using the table and column name. I tried myself creating a new foreignKey on my table and then updating the model and everything goes fine. You should'nt have problems with that.
I think I've done enough research on this subject and I've only got a headache.
Here is what I have done and understood: I have restructured my MySQL database so that I will keep my user's data in different tables, I am using foreign keys. Until now I only concluded that foreign keys are only used for consistency and control and they do not automatize or do anything else (for example, to insert data about the same user in two tables I need to use two separate insert statements and the foreign key will not help to make this different or automatic in some way).
Fine. Here is what I want to do: I want to use Sequelize to insert, update and retrieve data altogether from all the related tables at once and I have absolutely no idea on how to do that. For example, if a user registers, I want to be able to insert the data in the table "A" containing some user information and in the same task insert in the table B some other data (like the user's settings in the dedicated table or whatever). Same with retrievals, I want to be able to get an object (or array) with all the related data from different tables fitting in the criteria I want to find by.
Sequelize documentation covers the things in a way that every thing depends on the previous one, and Sequelize is pretty bloated with a lot of stuff I do not need. I do not want to use .sync(). I do not want to use migrations. I have the structure of my database created already and I want Sequelize to attach to it.
Is it possible insert and retrieve several rows related at the same time and getting / using a single Sequelize command / object? How?
Again, by "related data" I mean data "linked" by sharing the same foreign key.
Is it possible insert and retrieve several rows related at the same
time and getting / using a single Sequelize command / object? How?
Yes. What you need is eager loading.
Look at the following example
const User = sequelize.define('user', {
username: Sequelize.STRING,
});
const Address = sequelize.define('add', {
address: Sequelize.STRING,
});
const Designation = sequelize.define('designation', {
designation: Sequelize.STRING,
});
User.hasOne(Address);
User.hasMany(Designation);
sequelize.sync({ force: true })
.then(() => User.create({
username: 'test123',
add: {
address: 'this is dummy address'
},
designations: [
{ designation: 'designation1' },
{ designation: 'designation2' },
],
}, { include: [Address, Designation] }))
.then(user => {
User.findAll({
include: [Address, Designation],
}).then((result) => {
console.log(result);
});
});
In console.log, you will get all the data with all its associated models that you want to include in the query
I want to implement MySQL full text search with sequelize. The version "sequelize": "^3.23.6". I tried to research about this but could not find =the documentation that guides how to implement this.
Here is the link that says FullText is supported by sequelize:
https://github.com/sequelize/sequelize/issues/2979
But there is not exact documentation on how to do it and how to do a full text search query with sequelize.
Any links advice would be helpful
Thanks !
Since we now have the error message in recent Sequelize that looks like this:
Unhandled rejection Error: Support for literal replacements in the where object has been removed.
The solution would be to provide replacements manually
Payments.findAll({
where: Sequelize.literal('MATCH (SomeField) AGAINST (:name)'),
replacements: {
name: 'Alex'
}
});
Use arrays for more complex conditions:
Payments.findAll({
where: [
{ State: 'Paid' },
Sequelize.literal('MATCH (SomeField) AGAINST (:name)')
],
replacements: {
name: 'Alex'
}
});
Sequelize doesn’t fully support the full-text search feature. We can add a FULLTEXT index as easy as any other index. But operators supporting the MATCH (column) AGAINST (value) syntax haven’t been implemented.
My current solution to the problem consists of creating a regular model:
module.exports = (sequelize, DataTypes) => {
const Book = sequelize.define('Book', {
title: DataTypes.STRING,
description: DataTypes.TEXT,
isActive: DataTypes.BOOLEAN
}, {
indexes: [
// add a FULLTEXT index
{ type: 'FULLTEXT', name: 'text_idx', fields: ['description'] }
]
});
return Book;
};
And using a raw query for querying:
const against = 'more or less';
models.Book.find({
where: ['isActive = 1 AND MATCH (description) AGAINST(?)', [against]]
}).then((result) => {
console.log(result.title);
});
Using only MySQL it's not possible to get correct results if you trying to search for inflectional words, synonyms etc. MySQL developers consider adding dictionaries for full-text search (https://dev.mysql.com/worklog/task/?id=2428), but who knows when we will see it.
If you have to stick with MySQL, I suggest to take a look at Sphinx. It works properly with synonyms and inflectional words.
Since Sequlize does not support for fullText search.
Here is another approach for searching a string from a table
models.sequelize.query(
"SELECT * FROM tableName WHERE CONCAT(field1, '', field2, '', field3, '', field4 ) LIKE \"%" + keyword + "%\"",
{type: models.sequelize.QueryTypes.SELECT}).then(res => {
})
another approach, using single migration file
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.createTable(
'Products',
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
},
},
).then(() => queryInterface.addIndex('Products', ['name'], { type: 'FULLTEXT' })),
down: (queryInterface) => queryInterface.dropTable('Products'),
};
New updated Answer, Here I am searching for Locations that match my searchString.
Location.findAll({
where: {
name: sequelize.where(
sequelize.fn("LOWER", sequelize.col("name")),
"LIKE",
"%" + "You search text here"+ "%". <==== add your searchString Here
),
},
})