Currently, I am building a web app with nodejs + mysql and sequelize as ORM. I want to create some views like we do in mysql, but I can't find any option in Sequelize to create views.
Is there any ORM where it's possible to create views? Or is it possible to do it with sequelize?
There are no builtin methods for managing views in Sequelize, but you can create them using plain SQL queries and manage them with normal Sequelize models.
If you're using umzug for your migrations as recommended by the Sequelize docs, you can create your view using a migration similar to this:
const view_name = 'my_view';
const query = '<SQL QUERY THAT RETURNS YOUR VIEW>';
module.exports = {
up: function (database, Sequelize) {
return database.query(`CREATE VIEW ${view_name} AS ${query}`);
},
down: function (database, Sequelize) {
return database.query(`DROP VIEW ${view_name}`);
}
}
For view changes or updates, you should use the CREATE OR REPLACE VIEW syntax to ensure you can roll back your schema changes - avoid the tempation to DROP the old view and CREATE a new one!
const view_name = 'my_view';
const original_query = '<SQL QUERY THAT RETURNS YOUR VIEW>';
const new_query = '<SQL QUERY THAT RETURNS YOUR UPDATED VIEW>';
module.exports = {
up: function (database, Sequelize) {
return database.query(`CREATE OR REPLACE VIEW ${view_name} AS ${new_query}`);
},
down: function (database, Sequelize) {
return database.query(`CREATE OR REPLACE VIEW ${view_name} AS ${original_query}`);
}
}
The exact code snippets will, of course, vary depending on how you've been setting up migrations so far.
Once your migration is all set, create a Sequelize model representing your view schema as usual, using the view name as your table name. All of the find family functions should work as expected, while update, delete, and create should be expected to fail.
You can reference the Sequelize docs for raw queries, and this example repo for using Umzug with Sequelize. The only formal documentation I can find for Umzug itself is on its NPM page.
Related
I am new to sequelize. I am not sure how to convert this MySql query so that I can use it in my node.js file.
MySql query:
SELECT Rtrim(Ltrim(childstatus)),TIMESTAMPDIFF(d,dob,now(3))
INTO #childstatus, #Ageday
FROM childdetails where registno=#registno
I have sequelize model for childdetails. I am not sure how to structure this query.
You can use Sequelize.fn to call these two functions indicating them in attributes option like this:
const details = await ChildDetials.findAll({
attributes: [
[Sequelize.fn('RTrim', Sequelize.fn('LTrim', Sequelize.col('childstatus'))), 'childsttaus'],
[Sequelize.fn('TIMESTAMPDIFF', Sequelize.literal('d'), Sequelize.col('dob'), Sequelize.fn('now', 3)), 'Ageday']
],
where: {
registno: registno
}
})
I'm looking for a way to save database entities changes for some entities. I mean I need to save in a database table all changes that are done on some tables (add, modify / delete) with ability to track user which did the change.
I'm working on NextJS with a custom ExpressJS server and MYSQL database were I use Prisma as ORM. I think it's maybe possible to write an ExpressJS middleware but I have yet no idea how to do it and asking myself if any library already exist.
Usually I work on PHP Symfony and used to manage this StofDoctrineExtensionsBundle which is great and works as expected. But my current project is a Typescript project only with Express/NextJS/React/Prisma/MYSQL.
Any feedback from your knowledge will be very appreciate.
Thank's in advance.
Regards,
Gulivert
EDIT: My current API which has to be moved to Express/NextJS is still running on Symfony and the table where all changes is logged looks like this :
{
"id": 59807,
"user": "ccba6ad2-0ae8-11ec-813f-0242c0a84005",
"patient": "84c3ef66-548a-11ea-8425-0242ac140002",
"action": "update",
"logged_at": "2021-11-02 17:55:09",
"object_id": "84c3ef66-548a-11ea-8425-0242ac140002",
"object_class": "App\\Entity\\Patient",
"version": 5,
"data": "a:2:{s:10:\"birth_name\";s:2:\"--\";s:10:\"profession\";s:2:\"--\";}",
"username": "johndoe",
"object_name": "patient",
"description": null
}
Explanation about database columns:
user => relation to user table
patient => relation to patient table
action => can be "create"/"update"/delete"
logged_at => date time where the change was done
object_id => entity row ID where an entity get a change
object_class => the entity updated
version => how many time the object was change
data => all data changed during the modification
username => the username of logged user did the change
object_name => a string to identify the object modified without
using the namespace of object_class
description => a value that can be update on some specific change * during usually the action delete to keep a trace what was deleted for instance
You might find prisma middleware useful for this.
Check out the example with session data middleware which is somewhat similar to what you're doing.
For your use-case the middleware might look like something like this:
const prisma = new PrismaClient()
const contextLanguage = 'en-us' // Session state
prisma.$use(async (params, next) => {
// you can find all possible params.action values in the `PrismaAction` type in `.prisma/client/index.d.ts`.
if (params.model == '_modelWhereChangeIsTracked_' && (params.action == 'create' || params.action == "update")) {
// business logic to create an entry into the change logging table using session data of the user.
}
return next(params)
})
// this will trigger the middleware
const create = await prisma._modelWhereChangeIsTracked_.create({
data: {
foo: "bar"
},
})
However, do note that there are some performance considerations when using Prisma middleware.
You can also create express middleware for the routes where you anticipate changes that need to be logged in the change table. Personally, I would prefer this approach in most cases, especially if the number of API routes where changes need to be logged is known in advance and limited in number.
We are building an application using nodejs, mysql using sequelize. Sequelize makes development more easy when it comes to deal with database. Nice concept. I need your help in Sequelize. We have gone far with software development using Sequelize using MySQL database. We have built many stored procedures in MySQL which takes care on complex business calculation/ logic.
We faced below two issues while deal with Stored procedure which contains temporary table data and sequelize.
Case 1:
I have created one stored procedure which returns the data from temporary table. The stored procedure is creating the temporary table if not exist.
CREATE PROCEDURE `Sproc_GetCountryList` ()
BEGIN
Drop temporary table if exists tempCountry;
Create temporary table if not exists tempCountry
select countryID, countryName, countrySortCode
from countrymst;
END
Now when I call it using sequelize and transaction, (see minimal example code below), it returns duplicate data on subsequent call from UI immediately. but when I keep few seconds difference in call (e.g. around 10 seconds) then it returns the proper result.
getCountryList: (req, res) => {
const {
sequelize
} = req.app.locals.models;
return sequelize.transaction().the(t) => {
return sequelize.query('CALL Sproc_GetCountryList ()', {
type: sequelize.QueryTypes.SELECT,
transaction: t
}).then((response) => {
t.commit();
return resHandler.successRes(res, 200, STATE.SUCCESS, _.values(_.first(response)));
}).catch(function (err) {
t.rollback();
});
}).catch(function (err) {
t.rollback();
});
},
Each stored procedure contains one or two temporary table and as per MySQL, temporary table scope is limited to per session. So user having different session will have multiple temporary table but with its own set of temporary data. (Ref. https://www.oreilly.com/library/view/mysql-cookbook-2nd/059652708X/ch04s04.html) Do you have any suggestion how I can deal with session with sequelize so that it always return the unique data on subsequent call.
Case 2:
I have created one stored procedure which returns the data from temporary table. The stored procedure is creating the temporary table if not exist and also drops the temporary table at the end of stored procedure.
CREATE PROCEDURE `Sproc_GetCountryList` ()
BEGIN
Create temporary table if not exists tempCountry
select countryID, countryName, countrySortCode
from countrymst;
Drop temporary table tempCountry;
END
Now when I call it using sequelize, (see minimal example code below), subsequent call from UI immediately, and returns the error like, column 'countryName' is undefined.
getCountryList: (req, res) => {
const {
sequelize
} = req.app.locals.models;
sequelize.query('CALL Sproc_GetCountryList ()', {
type: sequelize.QueryTypes.SELECT
}).then((response) => {
return resHandler.successRes(res, 200, STATE.SUCCESS, _.values(_.first(response)));
}).catch(function (err) {
console.trace();
});
},
Can you please share you thought to prevent this kind of situation?
I have the following Employee model for a MySQL database:
var bcrypt = require('bcrypt');
module.exports = (sequelize, DataTypes) => {
const Employee = sequelize.define(
"Employee",
{
username: DataTypes.STRING,
password: DataTypes.STRING,
}, {}
);
return Employee;
};
Seeding the database is done by reading a .sql file containing 10,000+ employees via raw queries:
sequelize.query(mySeedingSqlFileHere);
The problem is that the passwords in the SQL file are plain text and I'd like to use bcrypt to hash them before inserting into the database. I've never done bulk inserts before so I was looking into Sequelize docs for adding a hook to the Employee model, like so:
hooks: {
beforeBulkCreate: (employees, options) => {
for (employee in employees) {
if (employee.password) {
employee.password = await bcrypt.hash(employee.password, 10);
}
}
}
}
This isn't working as I'm still getting the plain text values after reseeding - should I be looking into another way? I was looking into sequelize capitalize name before saving in database - instance hook
Your hooks won't be called until you use model's function for DB operation , so if you are running raw query , hooks will never be fired,
Reason : You can write anything inside your raw query , select/insert/update/delete anything , how does sequelize.js know that
it has to fire the hooks. This is only possible when you use methods
like
Model.create();
Model.bulkCreate();
Model.update();
Model.destroy;
And as per DOC raw query doesn't have hooks option to add.
And for MODEL queries you can check that it has option to
enable/disable hook.
I'm using sails.js and sails-MySQL and I want to connect to a MySQL database. I have tables, functions, and procedures in my workbench. now I want to know that is it necessary to create model files and define my schema again?
Yes, you can connect to your DB without defining models. However bare in mind that you will have to write raw queries every time. So first you need to define your DB connection in your datastores.js file. Then you can do the following in some of your controllers when you want to get something from your DB (say you have a table users and you want to get all of them):
var myDBStore = sails.getDatastore(); //gets the default datastore.
var query = "SELECT * FROM users;";
myDBStore.sendNativeQuery(query).exec(function (err, nativeResult) {
if (err) {
return res.send(err);
}
return res.send(nativeResult.rows);
});
or using the modern way in an async function:
var myDBStore = sails.getDatastore(); //gets the default datastore.
var query = "SELECT * FROM users;";
var nativeResult;
try {
nativeResult = await myDBStore.sendNativeQuery(query);
} catch (err) {
return res.send(err);
}
return res.send(nativeResult.rows);
More info here: https://sailsjs.com/documentation/reference/waterline-orm/datastores in section "Using datastores without a model"