Sequelize running migration results Cannot read property 'key' of undefined - javascript

I wanted to update column to set not null to false, however running db:migration fails with this error message:
Cannot read property 'key' of undefined
Here's the code of migration:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.changeColumn('Notes', 'title', {
allowNull: false
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.changeColumn('Notes', 'title', {
allowNull: true
});
}
};
As followed document, it seems nothing wrong with my code.
Table and field are exists, what am I wrong?

Just had this problem myself. From what I see in the source code Sequelize assumes you always provide the type when changing the column. I see it's also in the documentation you linked: "Please make sure, that you are completely describing the new data type."

Just a tip how you can fix it. I think query interface object is not able to find the name or column of the table which has to be migrated. Can you just print your Sequelize object and models inside it and put the same name which your Sequelize object holds. I have tried the same library and it works like a charm.

You must have to provide the column type either you want to change it or not.
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.changeColumn('Notes', 'title', {
type: Sequelize.STRING,
allowNull: false
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.changeColumn('Notes', 'title', {
type: Sequelize.STRING,
allowNull: true
});
}
};

Related

How do I specify the correct defaultValue for Sequelize.ARRAY(Sequelize.INTEGER)?

I'm switching from the concept of a hard DATABASE reboot (sync({force:true})) to migrations.
When creating a migration ( nps sequelize-cl model:generate ... ) and then inserting it into the migration database ( npx sequelize-cli db:migrate), I get the following error:
Sequelize CLI [Node: 18.10.0, CLI: 6.6.0, ORM: 6.28.0]
Loaded configuration file "config/config.json".
Using environment "development".
== 20230130114154-create-chat: migrating =======
ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[] DEFAULT , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMA' at line 1
My Migration file:
"use strict";
/** #type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable("Chat", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
},
user_ids: {
type: Sequelize.ARRAY(Sequelize.INTEGER),
defaultValue: [],
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable("Chat");
},
};
The problem is how the string defaultValue is recognized: []. [] - assumes not an array, but an array of values. For example, [0] is recognized as 0 for the default field, and an empty array as a void.
The question is how to specify the default value for the field:
... {
type: Sequelize.ARRAY(Sequelize.INTEGER),
defaultValue: ...,
}
Thanks a lot in advance for the answer.
P.S. Somehow this problem was solved once, unfortunately the solution was not preserved.
array is supported only for PostgreSQL

How to add new ENUM value to existing table using sequalize in PostgreSQL database?

Let's say I created some table in my PostgreSQL database using sequelize:
status: {
type: Sequelize.ENUM(["approved", "rejected", "new"]),
allowNull: true
},
As you can see, there are 3 ENUM values, now, I need to add one more ENUM value using new migration. I was trying to do this something like this, but it doesn't work:
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
return queryInterface.sequelize.query("ALTER TABLE risky_transactions ALTER COLUMN status ADD VALUE 'question';")
},
async down (queryInterface, Sequelize) {
}
};
So, how can I do this? No matter how, using query or pure sequelize syntax.
Thanks!

How to use Sequelize associations with .then in controller

This is my ToWatch Model in toWatch-model.js file which in code has UserModel->ToWatch 1:1 relationship and has ToWatch->MovieModel 1:M relationship.
const Sequelize = require('sequelize');
const sequelize = require('./../common/db-config');
const MovieModel = require ("./movie-model");
const UserModel = require("./user-model");
const Model = Sequelize.Model;
class ToWatch extends Model{}
ToWatch.init({
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id_towatch'
},
date: {
type: Sequelize.DATE,
allowNull: false,
field: 'date'
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'id_user',
references:{
model: UserModel,
key: "id"
}
},
movieId: {
type: Sequelize.INTEGER,
allowNull: false,
field: 'movie_id_towatch',
references:{
model: MovieModel,
key: "id"
}
},
},
{
sequelize,
modelName: 'towatch',
tableName: 'towatch',
timestamps: false
// options
});
//Here is the relation ************
UserModel.hasOne(ToWatch, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'fk_foreign_key_towatch'
}
});
ToWatch.belongsTo(UserModel);
ToWatch.hasMany(MovieModel, {
foreignKey: {
type:Sequelize.DataTypes.INTEGER,
allowNull:false,
name:'movie_id_towatch'
}
});
MovieModel.belongsTo(ToWatch);
module.exports = ToWatch;
I watched many tutorials, but being my first time trying to make a method that will return everything including something from my other table via ID, I wasn't sure where to put and how to put data that I need in this method, considering it has .then(data=>res.send). Tutorials were doing it other ways by fetching or using async-await, and even documentation didn't help me here. Can somebody tell me what to put and where inside this method, that is inside toWatch-controller.js file for me being able to see let's say all the movie data (title,img,date) ,as an array I think, of the getToWatch method.
const ToWatch = require('./../models/toWatch-model');
module.exports.getToWatch = (req,res) => {
ToWatch.findAll().then(toWatch => {
[WHAT DO I PUT HERE?]
res.send(toWatch);
}).catch(err => {
res.send({
status: -1,
error:err
})
})
}
I need something like this ToWatch{
color:red,
cinema:"MoviePlace",
movieId{title:"Anabel", img:"URL", date:1999.02.23}
As I understood your question right, what you trying to do is return toWatch model instances with including User and Movie models.
To do so you can pass options in findAll() method like below:
ToWatch.findAll({include: [{model: User}, {model: Movie}]})... //and rest of your code
Or alternatively to keep your code clean you can use scopes:
// below the toWatch-model.js file
ToWatch.addScope('userIncluded', {include: {model: User}})
ToWatch.addScope('movieIncluded', {include: {model: Movie}})
And in the getToWatch method:
// you can pass several scopes inside scopes method, its usefull when you want to combine query options
ToWatch.scopes('userIncluded', 'movieIncluded').findAll()... //rest of your code
For more information check out sequelize docs

After adding `runValidators: true`, my Mongoose update function is erroring with ` cannot read property 'ownerDocument' of null `

Thank you in advance for any help that anyone can provide.
I currently have something like below for my mongoose schema:
const personSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 3,
unique: true
},
number: {
type: String,
validate: {
// below regex matches 8 digits together regardless of any other characters in between that are not digits
validator: function(v) { return /([^\d]*\d){8,}/.test(v) }
},
required: true
},
})
// applying the uniqueness validator
personSchema.plugin(uniqueValidator)
personSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
}
})
module.exports = mongoose.model('Person', personSchema)
And in my index.js for my function for handling update calls, it looks like this:
app.put('/api/persons/:id', (request, response, next) => {
const body = request.body
const person = {
name: body.name,
number: body.number,
}
Person.findByIdAndUpdate(request.params.id, person, {new: true})
.then(updatedPerson => {
response.json(updatedPerson)
})
.catch(error => next(error))
})
So initially, this worked perfectly fine, but after I add the runValidators: true option which looks like this now:
Person.findByIdAndUpdate(request.params.id, person, {new: true, runValidators: true,})
I get this new error that states:
"error": "Validation failed: name: Cannot read property 'ownerDocument' of null"
I'm not sure what ownerDocument even is, and I'm also unclear on why making the update function run the validator is causing this as well. Any help would be appreciated!
If you're using the mongoose-unique-validator plugin with findOneAndUpdate and related methods, you need to set the context option to 'query' to set the value of this to the query object in validators.
Person.findByIdAndUpdate(request.params.id, person, {
new: true,
runValidators: true,
context: 'query',
})
https://github.com/blakehaswell/mongoose-unique-validator#find--updates

How do I override a sequelize defaultValue function for testing purposes?

I'm trying to add unit/integration testing to my sequelize project, and I'm running into a problem when moving from postgres dialect to sqlite. I am attempting to override the 'defaultValue' function on 'id'. This results in the syntax for CREATE TABLE being correct, but the original defaultValue is used in the INSERT statement generated by .create().
I have created a minimal sample project that illustrates the problem I'm describing with a failing test.
Here's the relevant code snippet:
User = sequelize.define('User', {
id: {
type: Sequelize.UUID,
field: 'id',
defaultValue: sequelize.literal("uuid_generate_v1mc()"),
primaryKey: true
},
name: {
type: Sequelize.STRING,
field: "first_name"
},
});
// why doesn't setting these attributes override the default value
// provided by User.create?
User.attributes.id.defaultValue='b9c96442-2c0d-11e6-b67b-9e71128cae77';
User.tableAttributes.id.defaultValue='b9c96442-2c0d-11e6-b67b-9e71128cae77';
What's the best way to inject or mock the defaultValue function?
The answer would miss the "why" part, but here is how I made it work:
before(function() {
// Define a table that uses a custom default value
User = sequelize.define('User', {
id: {
type: Sequelize.UUID,
field: 'id',
defaultValue: sequelize.literal("uuid_generate_v1mc()"),
primaryKey: true
},
name: {
type: Sequelize.STRING,
field: "first_name"
},
});
User.attributes.id.defaultValue.val = '"b9c96442-2c0d-11e6-b67b-9e71128cae77"';
return sequelize.sync();
});
Though, I suspect there should be an easier way to achieve the same result.
What is interesting is that if the defaultValue would not be literal or fn and be, say, a string value instead, things would be much easier - we could've just added a hook:
User.beforeCreate(function (user) {
user.dataValues.id = 'b9c96442-2c0d-11e6-b67b-9e71128cae77';
});
I suggest you to seek the answers for the "why" question at the sequelize issue tracker.

Categories

Resources