So i have this sequelize model of an Organization:
module.exports = (sequelize, Sequelize) => {
const Organization = sequelize.define("organization", {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
organizationName: {
type: Sequelize.STRING,
allowNull: false,
notEmpty: true,
unique: {
args: 'username',
msg: 'This username is already taken!'
}
},
emailAddress: {
type: Sequelize.STRING,
allowNull: false,
validate: {
isEmail: true
},
unique: {
args: 'email',
msg: 'The email is already taken!'
}
},
physicalAddress: {
type: Sequelize.STRING,
allowNull: true
},
city: {
type: Sequelize.STRING,
allowNull: false
},
country: {
type: Sequelize.STRING,
allowNull: false
},
phone: {
type: Sequelize.INTEGER,
allowNull: true
},
websiteAddress: {
type: Sequelize.STRING,
allowNull: true
}
}, {
timestamps: false,
underscored: true,
freezeTableName: true
});
return Organization;
};
When the user registers with a new Organization i want to make sure that the username entered is unique.
My question is... Is my implementation enough? Or should i be doing a organization.find before insert?
It does work but I'm worried.
I am aware that with the above method the id gets auto incremented even if validation fails. But are there any other issues?
You are relying on the DB kicking out an error if the name is not unique. This should be a last resort really and would recommend you query your table before you attempt an insert. However, you could look at the upsert style operations like findOrCreate
Additional Thought:
It would be less strain on your db, more scalable, and a better experience for your users, if you kept a cached list of existing usernames and searched that before you attempt the insert - as part of your validation process. Ideally, this would be called from an ajax query when the user has entered the organizational name.
UPDATE on some catching ideas:
Redis is a great start. It's widely adopted and implemented at all major providers like AWS, Heroku, Azure, etc. It's simple to provision and effortless to set up locally. Having a central, shared cache allows you to share data between your web/api instances, will be substantially faster to query, and takes the strain off your DB when cached data will suffice. I like the ioredis driver.
Related
Is this possible or must the entire project be nuked and redone?
Example: I want to add a "breedId" column to a dogs table to reference model "Breeds"
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Dog', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING(50),
allowNull: false
},
description: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Dog');
}
};
Since you appear to be using migrations, you will have a pretty easy time adding onto your tables.
Create another migration, and use queryInterface.addColumn(tableName: string, columnName: string, options: object) for the up, and queryInterface.removeColumn(tableName: string, columnName: string) for the down.
If you are using sequeilze.sync() to build your tables from the models, your options are worse. You either need to pass {force: true} into the .sync() method, which will drop the current tables before rebuilding them with the attributes in your models. Or, to preserve data you can omit {force: true} by manually adding the columns and foreign key constraints to the database, and add the corresponding attributes to the models.
UPDATE
someone below suggested adding in a model id for shoutouts and I'm no longer getting the error, but now nothing is being saved to my database?
adding in the new information below:
I have a one to many relationship between users and shoutouts. Both models have email property,
I am trying to use a magic method to setup the shoutout. When I use user.createShoutout()
I can generate the shoutout, but the email property doesn't show up in the database.
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
//NEW
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
associations:
User.hasMany(Shoutouts)
Shoutouts.belongsTo(User)
User.hasMany(Emails)
Emails.belongsTo(User)
when I use user.AddShoutout()
as follows:
let paramsObj = {
name: addEmail.firstName,
email:addEmail.email,
message: 'test msg',
userId: 3
}
//NEW
let id = 1;
const addInfo = await userThree.addShoutout(id,paramsObj)
//NEW
not getting the object error anymore, in fact not seeing any errors. But when I look in my shoutouts table nothing is getting added.
when I console.log addInfo
The user who tried to create the shoutout gets returned?
I need help with trying to get this user model magic method to generate a new shoutout!
Thanks for reading this, and any advice!
Your email field is nested within name field
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: { # <----------------------------- nested too deep
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
When I am working on my React social media project, I want to add a "Friend connect request" feature. I use MongoDB, and here is my "User Model" below.
Now my "Friends" is nested inside UserSchema, but feels like this is not right.
What if I want more stats, for example pending, rejected, block sender...
Let's say: User A sent connect request to B, then B should know, and when B try to send out requests to friends, A should be excluded.
const UserSchema = new Schema({
username: {
type: String,
required: [true, 'User Name is required'],
lowercase: true,
},
email: {
type: String,
required: [true, 'Email or Phone number is required'],
unique: true,
lowercase: true,
},
password: {
type: String,
required: [true, 'Password is required'],
},
thumbnail: {
type: String,
default: 'https://cdn.pixabay.com/photo/2016/08/09/17/52/instagram-1581266_960_720.jpg',
},
createAt: {
type: Date,
default: Date.now,
},
friends: [
{
type: Schema.Types.ObjectId,
ref: 'user',
}
],
}),
I am newbee, first time meet this kind of question, and don't know the design logic behind this feature. Could anyone has experience give me some advances (welcome all of frontend and backend, database design)?
I am new developer and am trying to teach myself Sequelize and mysql with some little test projects. What I have right now is a little RPG team strength analyzer. I have a SQL table of Units, which has schema (id, name, elementOne, elementTwo) - integer, string, string, string.
For now, the elementOne and ElementTwo tables are both the same 18 string values because I couldn't figure out how to set up the Sequelize query with foreign keys refs to the same table (e.g. just 'elements').
Adding to the Unit table works fine on a local server, but breaks on Heroku ONLY when trying to add a third unit with the following error:
Error was: { SequelizeForeignKeyConstraintError: Cannot add or update a child
row: a foreign key constraint fails (`heroku_f4daeab1e260595`.`units`,
CONSTRAINT `units_ibfk_1` FOREIGN KEY (`id`) REFERENCES `elementtwos` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE)
Here are all the tables and the relationship declarations.
const Unit = sequelize.define('unit', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
},
image: {
type: Sequelize.STRING,
allowNull: true,
unique: false
},
elementOne: {
type: Sequelize.INTEGER,
allowNull: true,
references: {
model: Element,
key: 'id'
}
},
elementTwo: {
type: Sequelize.INTEGER,
allowNull: true,
defaultValue: 10001,
references: {
model: ElementTwo,
key: 'id'
}
}
});
const Element = sequelize.define('element', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
}
});
const ElementTwo = sequelize.define('elementtwo', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: false
}
});
After these are all loaded, I set up the following:
Unit.belongsTo(Element, {foreignKey: 'elementOne'});
Unit.belongsTo(ElementTwo, {foreignKey: 'elementTwo'});
ElementTwo.hasMany(Unit, {foreignKey: 'id'});
Element.hasMany(Unit, {foreignKey: 'id'});
And this is the query that Sequelize is doing (in a Unit.create({...}):
INSERT INTO `units`
(`id`,`name`,`image`,`elementOne`,`elementTwo`,`createdAt`,`updatedAt`) VALUES
(DEFAULT,'raichu','http://longimgurl.png',13,10001,'2017-06-14
12:57:54','2017-06-14 12:57:54');
If anyone can offer any advice it would be greatly appreciated.
this is mysql error and because you define foreign key constraint on you table and try to insert unavailable value in fk field that does not exit in target table,
check element and elementTwo table and make sure this values are available
So I have two tables: Class and Course. Each Class has a course_id that defines what type of course it is on the Course table. Here are my models:
const Class = sequelize.define('class', {
class_date: Sequelize.DATE,
begin_time: Sequelize.TIME,
end_time: Sequelize.TIME,
max_capacity: Sequelize.INTEGER,
is_published: Sequelize.BOOLEAN,
training_facility_id: Sequelize.INTEGER,
state_id: Sequelize.INTEGER,
registration_deadline: Sequelize.DATE,
course_id: Sequelize.INTEGER,
is_report_60_generated: Sequelize.BOOLEAN,
completed_by_user_id: Sequelize.INTEGER
}, {
timestamps: false,
freezeTableName: true
})
const Course = sequelize.define('course', {
code: Sequelize.STRING,
name: Sequelize.STRING
}, {
timestamps: false,
freezeTableName: true
})
When I hit the classes endpoint, I get a array of classes. How would I set up the query to respond with the course name and code for each class instead of just the course_id?
You will need to create a relationship between the Class and Course models. If you specify the underscored: true option in the Model definition it won't use camel case and will automatically create the Class.course_id column, so you don't need to define it (the same probably goes for completed_by_user_id).
const Class = sequelize.define('class', {
class_date: Sequelize.DATE,
begin_time: Sequelize.TIME,
end_time: Sequelize.TIME,
max_capacity: Sequelize.INTEGER,
is_published: Sequelize.BOOLEAN,
training_facility_id: Sequelize.INTEGER,
state_id: Sequelize.INTEGER,
registration_deadline: Sequelize.DATE,
// this will be auto-created by the relationship
// course_id: Sequelize.INTEGER,
is_report_60_generated: Sequelize.BOOLEAN,
// you probably want a relationship here as well
completed_by_user_id: Sequelize.INTEGER
}, {
timestamps: false,
freezeTableName: true,
// use underscored names
underscored: true,
})
const Course = sequelize.define('course', {
code: Sequelize.STRING,
name: Sequelize.STRING
}, {
timestamps: false,
freezeTableName: true,
underscored: true,
})
Based on your data model it seems as though each Class will require an associated Course with different attributes like start time, etc, so you will tell Sequelize that each Class belongsTo() a Course.
// tell Sequelize that once course will be assigned to many classes, and it is required (not null)
Class.belongsTo(Course, { foreignKey: { allowNull: false } })
Once they are related you can use the include option value to specify a model to join to your primary query. If you use as in the relationship you must specify it here as well.
// do a joined query using "include"
Class.findAll({
include: [
{
model: Course
}
]
})