Sequelize Migration: update model after updating column attributes - javascript

I will get through to the point already. I'm having a problem of updating the rows after I have changed the status column attribute.
up: function(queryInterface, Sequelize) {
return queryInterface.changeColumn('projects', 'status', {
type: Sequelize.ENUM('processing', 'unassigned', 'ongoing', 'completed'),
allowNull: false,
defaultValue: 'unassigned'
}).then(function() {
return Project.update({
status: 'unassigned'
}, {
where: {
status: 'processing'
}
});
});
}
The Project.update() seems not working in any case but changing the attributes of the column works.
Any idea guys? I'm somehow a newbie in sequelize and any idea would be a great help. Thanks.

Depending on how you execute the migration ( via sequelize-cli or programmatically via umzug ). There is a different way to expose the table via the ORM.
In your case you have queryInterface passed as an argument to your function. So you can do a "raw query" via the attached sequelize property.
up: function(queryInterface, Sequelize) {
return queryInterface.changeColumn('projects', 'status', {
type: Sequelize.ENUM('processing', 'unassigned', 'ongoing', 'completed'),
allowNull: false,
defaultValue: 'unassigned'
}).then(function() {
return queryInterface.sequelize
.query("UPDATE projects SET status='unassigned' WHERE status='processing'");
});
}
By doing this you will make a raw Query to your database.
You can check out this gist for more details on an advanced way of using the ORM inside the migration.
I'm a fan of using umzug programmatically, which executes the migrations and also provides the initialized models of your database. If you configure it properly, you will benefit the exposed models ( e.g. sequelize.model('project').update() ) and have a better looking code.

Related

Firebase query of child key

I have the next structure in my firebase database:
{
events: {
event_1:{
startdate: 120934210,
enddate: 120934211,
members: {
uid_1: true,
uid_2: true,
...
}
},
event_2:{
startdate: 120934210,
enddate: 120934211,
members: {
uid_2: true,
uid_3: true,
...
}
},
...
}
}
I have a node event and every child is an event, each event have a list of members. The question is, how can I do a query for all events of a certain member? For example, all events with member uid_2. I'm using angularfire2 and angular 4. I'm trying to do something like that:
db.list('events/',ref => ref.orderByChild('members').equalTo(uid))
please help me.
Your current data structure allows you to easily find the members of a specific event. If does not allow you to easily determine the events for a specific user. To allow that, you should add an inverted data structure.
It is also recommended to not nest different entity types, but instead store them in top-level nodes.
For your data this leads to four likely top-level nodes:
users: {
$uid: { ... }
},
events: }
$eventid: { ... }
},
event_users: {
$event_id: {
$uid: true
}
},
user_events: {
$uid: {
$event_id: true
}
}
Now you can easily read (without querying) the members for an event, and the events for a user.
I also recommend you check out:
This great article on NoSQL data modeling
Many to Many relationship in Firebase
http://stackoverflow.com/questions/40656589
The Firebase for SQL developers video series

Ignore default model attributes in SailsJS for 1 specific model

Hi everyone im stuck at using a model of a specific table of a mysql database. I am using 2 different databases in my SailsJS application. One of the two databases has been created before the SailsJS application, so the tables in this database doesn't have the default attributes configured in config/models.js.
This causes an error when I try to call for example the find() function on the model that uses the older database because it misses a column. See following error:
: ER_BAD_FIELD_ERROR: Unknown column 'tbl_user.deleted' in 'field list'
I don't want to add the default attributes to the older database columns, so is it possible to ignore the default attributes configured in config/models.js for specific models?
After trying a few things i came up with the following solution.
Just add the default attributes to your model but add it as an function.
module.exports = {
connection: connection,
migrate: 'safe',
tableName: 'tbl_name',
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK: false,
schema: true,
attributes: {
id: {
columnName: 'id',
type: 'string',
primaryKey: true
},
name: {
columnName: 'name',
type: 'string'
},
email: {
columnName: 'email',
type: 'string'
},
deleted: function(){
var obj = this.toObject();
delete obj.deleted;
return obj;
},
createdBy: function(){
var obj = this.toObject();
delete obj.createdBy;
return obj;
}
}
};
In this example the attributes deleted and createdBy are default attributes in config/models.js. I made a function of these attributes in the specific model. In this function i delete this attribute and return the object without the deleted attribute.

sequelize saving multiple objects that assosiates

I wasnt quite sure what to call this question but here is my setup:
var AcademyModule = sequelize.define('academy_module', {
academy_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
module_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
module_module_type_id: DataTypes.INTEGER,
sort_number: DataTypes.INTEGER,
requirements_id: DataTypes.INTEGER
}, {freezeTableName: true,}
With the following assosiation:
Requirements = sequelize.define('requirements', {
id: DataTypes.INTEGER,
value: DataTypes.STRING,
requirement_type_id: DataTypes.INTEGER
}, {freezeTableName: true});
AcademyModule.belongsTo(Requirements, {foreignKey: 'requirements_id'});
Now as you can see from my table setup i would have to save a row in requirements table and then use the inserted id to insert into the academy_module table.
for this i created the following:
add: function (requirements,academyModule,onSuccess, onError) {
var academyModule = academyModule;
if(requirements == null) {
AcademyModule.build(this.dataValues)
.save().ok(onSuccess).error(onError);
} else {
if(requirements.requirement_type_id == '1') {
requirements.value = requirements.module.id;
}
Requirements.create(requirements).then(function(createdReq) {
var associationPromises = [];
associationPromises.push(AcademyModule.create(this.dataValues));
return sequelize.Promise.all(associationPromises);
}).success(onSuccess).error(onError);
}
}
However in the then function i am unable to reach the academyModule object that contains the values that needs to be inserted.
This is a repeating problem for me and i really want to know how it is possible to connect so they do it automatically without doing small hacks
i have scouted the documentations but i havnt been able to find a single example of the above (which i find rather odd seeing as this is a fairly normal situation)
Jan's method
I tried to solve it using Jan's elegant method
However i am getting an error saying:
academy_module is not associated to requirements!
My code looks like this as for now:
var academyModule = academyModule;
if(requirements == null)
{
AcademyModule.build(this.dataValues)
.save().ok(onSuccess).error(onError);
}
else
{
requirements.academy_module = academyModule;
Requirements.create(requirements, {
include: [AcademyModule]
});
}
Funny thing here is t hat i have the assosiation:
AcademyModule.belongsTo(Requirements, {foreignKey: 'requirements_id'});
Requirements.hasOne(AcademyModule, {foreignKey: 'requirements_id'});
First of all, I cannot answer why you are having problems accessing academyModule - it should be available via simple javascript scoping.
There are some unexplained bits of your code... You are pushing a single promise to associationPromises - Why not just return that promise?
You are accessing this.dataValues to create an AcademyModule instance - this will normally be undefined inside a promise handler.
Your issue could be solved more elegantly with nested creation, which is in 2.0.5: https://github.com/sequelize/sequelize/pull/3386
First of all you need to create the reverse association from Requirements --> AcademyModule
Requirements.hasOne(AcademyModule, {foreignKey: 'requirements_id'});
This is needed because the Requirement is the 'main model', which is used to create the AcademyModule
requirements.academy_module = academy_module;
Requirements.create(requirements, {
include: [AcademyModule]
});
By setting academy_module on the requirements object, and adding include as the 2nd parameter (similar to how you use includes for find) both are created and associated in one go.
You'll need to modify your models slightly. With your current model definition the table will contain an id column, but sequelzie does not know that it is the primary key. You either need to remove id completely from the Requirements model (in which case sequelize will add it automatically and mark it as primary key), or add primaryKey to it:
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true // optional - only if you actually want AI :)
}

Sequalizejs adding paranoid configuration to an existing table

I created a table without the paranoid option, and i now want to change that table's definition to use paranoid.
I don't want to re-create the database since its already in production.
how can i do that using migrations?
should i use addColumn with deletedAt and just add the paranoid definition to the model, or is there a better way?
I added the deletedAt field using migration like this:
"use strict";
module.exports = {
up: function(migration, DataTypes, done) {
// add altering commands here, calling 'done' when finished
migration.addColumn(
'mytablename',
'deletedAt',
{
type: DataTypes.DATE,
allowNull: true,
validate: {
}
}
);
done();
},
down: function(migration, DataTypes, done) {
// add reverting commands here, calling 'done' when finished
migration.removeColumn('mytablename', 'deletedAt');
done();
}
};
And added the configuration:
paranoid: true,
to my model
It seems to work.
Does anyone have a better solution?
Small update.
According to the sequelize version 6.4.0(what I am currently using), the migration looks like this:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.addColumn(
'TABLE_NAME',
'deletedAt',
{
allowNull: true,
type: Sequelize.DATE
})
},
down: (queryInterface, Sequelize) => {
return queryInterface.removeColumn('TABLE_NAME', 'deletedAt')
}
};
I mean that the done method is not required.

EXTJS + Updating a store with the database ID after saving a grid

I'm trying to learn how to use the EXTJS grids for some simple CRUD operations over a table in a admin app.
I have a simple grid that allows someone to edit users, the store is defined as:
var userDataStore = new Ext.data.Store({
id: 'userDataStore',
autoSave: false,
batch: true,
proxy: new Ext.data.HttpProxy({
api: {
read: '/Admin/Users/All',
create: '/Admin/Users/Save',
update: '/Admin/Users/Save'
}
}),
reader: new Ext.data.JsonReader(
{
root: 'Data',
idProperty: 'ID',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message'
}, [
{ name: 'ID', type: 'string', allowBlanks: false },
{ name: 'NT_ID', type: 'string', allowBlank: false },
{ name: 'EMail', type: 'string', allowBlank: false },
{ name: 'Name', type: 'string', allowBlank: false },
{ name: 'Enabled', type: 'bool', allowBlank: false },
{ name: 'CurrentRoleCode', type: 'string', allowBlank: false}]
),
writer: new Ext.data.JsonWriter(
{
encode: false,
writeAllFields: true,
listful: true
})
});
This is bound to a grid, and I am able to load and save users without issue. The save button looks like this:
var saveButton = new Ext.Button({
text: 'Save',
disabled: true,
handler: function() {
userDataStore.save();
pageState.ClearDirty();
saveButton.disable();
}
});
However, when creating a new user, the JSON POST for the user is posted to the same REST service end point as "Update", with the only difference being that no ID value is posted (as one is only set in the store when loading from the server).
This works, and I am able to create users.
The save REST service emits back the created row with the new database ID, and I was under the assumption that EXTJS would automatically bind the new generated database ID to the row. This allows the user to further edit that row, and cause an update instead of a insert.
Instead, the row continues to have a blank user ID, so an additional save creates another new user.
So either:
EXTJS is supposed to resolve generated row ID's automatically and I am just doing something wrong.
I am supposed to manually reload the grid after each save with an additional REST call.
I've been looking at EXTJS documentation and forums, but I am unclear on the proper approach.
Can someone clarify?
EDIT: I tried returning Success = True in JSON to match the SuccessProperty, however this still didn't seem to work.
EDIT #2: So far the only thing I've found that works is doing "userDataStore.reload()" after saving, however because I was returning the contents of the store back after saving, I was hoping that EXTJS would understand that and update the row values.
I've got an idea that may help you. Let't suppose that user added a new
record in grid, in that moment add a new property newRecOrderNo to the record to
identify the record after response. When user will post data to server after
inserting you must get a new ID and associate it to newRecOrderNo
(like Map<Integer,Integer>). Then return json object like that :
{
success : true,
newIdes : {
1 : 23,
2 : 34
}
}
Then when you get response do set proper IDs to records:
userDataStore.each(function(rec){
if(rec.data.newRecOrderNo){
rec.data.ID = response.newIdes[rec.data.newRecOrderNo];
delete rec.data.newRedOrderNo;
}
})
})
Yes, it sets id (and also other fields, if server returns modified values of them), if create ajax backend returns record with set id, at least in extjs 4.1. You should return inserted record, with id set, under 'root' key as json dictionary, in this example root is 'Data', i.e.:
{
"Data": {
"ID": 8932,
"NT_ID": 28738273,
...
"CurrentRoleCode": "aaa",
},
"success": true
}
You need reload store with new params in savebtn handler
like
store.reload();
of course you can add more params to load action

Categories

Resources