I am trying to update a row in a given table using the following Sequelize query:
const handleEditProfile = async (req, res) => {
let medicalconditions = req.body.medicalconditions;
let allergies = req.body.allergies;
let bloodtype = req.body.bloodtype;
let weight = req.body.weight;
let height = req.body.height;
let userId = req.body.userid;
Profile.bulkCreate(
[{userId: userId, medicalconditions: medicalconditions, allergies: allergies, bloodtype: bloodtype, weight: weight, height: height}],
{updateOnDuplicate: ['medicalconditions', 'allergies', 'bloodtype', 'weight', 'height']}
)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(400).send(err);
})
};
This is what I get in the Postgres DB:
id | medicalconditions | allergies | bloodtype | weight | height | createdAt | updatedAt | userId
----+-----------------------------+--------------------+-----------+---------+------------+----------------------------+----------------------------+--------
74 | type 2 diabetes | penicillin | AB | 114 lbs | | 2023-02-13 14:56:21.789-06 | 2023-02-13 14:56:21.789-06 | 40
90 | hyperthyroidism | none | AB | 120 lbs | 5'4" | 2023-02-17 18:08:44.503-06 | 2023-02-17 18:08:44.503-06 | 40
As you can see, I looked up the "row" by the userId. I want to update the columns mentioned in "updateOnDuplicate" where userId = 40. However, instead of updating the row with the id = 74 and userId = 40, it creates a new row with the id = 90 and userId = 40. How can I fix this without mentioning the primary id?
const User = sequelize.define('user', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
uid: {
type: DataTypes.TEXT,
allowNull: false,
unique: true
},
firstName: {
type: DataTypes.TEXT,
allowNull: false
},
lastName: {
type: DataTypes.TEXT,
allowNull: false
},
DOB: {
type: DataTypes.TEXT,
allowNull: false
}
});
const Profile = sequelize.define('profile', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
medicalconditions: {
type: DataTypes.TEXT
},
allergies: {
type: DataTypes.TEXT
},
bloodtype: {
type: DataTypes.TEXT
},
weight: {
type: DataTypes.TEXT
},
height: {
type: DataTypes.TEXT
}
});
User.hasOne(Profile);
Profile.belongsTo(User);
If you want Profile records to be unique not only by PK but by userId as well you need an unique index/constraint in Profile table on userId. That way if you don't indicate PK in objects that about to be inserted PostgreSQL will look at fields values that correspond to any unique constraint to decide whether a record with such values already exists or doesn't.
Another benefit of having the unique index on userid that you can't create two records with the same userId even if you use an individual create calls.
Related
I want to retrieve users post by users logged in Id with following
conditions. As currently I am getting user-post as null.
1: If user posted a post. same user should be able to view his post
(if same user is not friend with anyone i.e ACCEPTED status).
2: If user posted a post, other users with whom he is friend should be
able to view post.
Basically I have used following database design,
1: Users id, first Name, last Name
2: Post id, post
3: UserPost
id,
postId, (referencing Post table),
userId (referencing User table)
4: Friendship id, userId, (referencing User table) friendUserId,
(referencing User table) friendshipStatus (e.g values ACCEPTED,
REJECTED)
Following is associations and query to retrieve the records schema,
1: User association
const Users = sequelize.define(
'Users',
{
id: {
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
firstName: {
type: DataTypes.STRING(20),
allowNull: true,
field: 'firstName'
},
lastName: {
type: DataTypes.STRING(20),
allowNull: true,
field: 'lastName'
},
{
tableName: 'users'
}
);
Users.associate = models => {
Users.hasMany(models.Friendships, { foreignKey: 'userId', as: 'friendship'});
Users.hasMany(models.UserPost, { foreignKey: 'userId', as: 'user-post'
});
}
2: Friendship association
const Friendships = sequelize.define(
'Friendships',
{
id: {
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
userId: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'users',
key: 'id'
},
field: 'userId'
},
friendUserId: {
type: DataTypes.BIGINT,
allowNull: false,
references: {
model: 'users',
key: 'id'
},
field: 'friendUserId'
},
friendshipStartDate: {
type: DataTypes.DATE,
allowNull: true,
field: 'friendshipStartDate'
},
friendshipStatusId: {
type: DataTypes.STRING(20),
allowNull: true,
field: 'friendshipStatusId'
},
},
{
tableName: 'friendships'
}
);
Friendships.associate = models => {
Friendships.belongsTo(models.UserPost, { foreignKey: 'userId', as: 'user-post' });
Friendships.belongsTo(models.Users, { foreignKey: 'id', as: 'user' });
};
3: Post association
const Post = sequelize.define(
'Post',
{
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
post: {
type: DataTypes.STRING(1000),
allowNull: false,
// defaultValue: '0',
field: 'Post'
},
postStatusId: {
type: DataTypes.INTEGER(10),
allowNull: true,
field: 'PostStatusId'
},
createdBy: {
type: DataTypes.INTEGER(10),
allowNull: true,
field: 'CreatedBy'
},
updatedBy: {
type: DataTypes.INTEGER(10),
allowNull: true,
field: 'ModifiedBy'
}
},
{
tableName: 'posts',
updatedAt: false,
createdAt: false
}
);
Post.associate = models => {
Post.belongsTo(models.Friendships, { foreignKey:'userId', as: 'friendship' });
Post.belongsTo(models.UserPost, { foreignKey: 'postId', as: 'userspost' });
Post.belongsTo(models.Users, { foreignKey: 'id', as: 'user' });
};
4: UserPost association
const UserPost = sequelize.define(
'UserPost',
{
id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true,
field: 'id'
},
userId: {
type: DataTypes.STRING(1000),
allowNull: false,
references: {
model: 'user',
key: 'id'
},
field: 'userId'
},
postId: {
type: DataTypes.INTEGER(10),
allowNull: true,
references: {
model: 'posts',
key: 'id'
},
field: 'postId'
}
},
{
tableName: 'user_posts',
updatedAt: false,
createdAt: false
}
);
UserPost.associate = models => {
UserPost.hasMany(models.Post, { sourceKey:'postId', foreignKey: 'id', as: 'post' });
UserPost.hasMany(models.Friendships, { foreignKey:'userId', as: 'friend'
});
};
Sequlize query
const result = await Users.findAll({
attributes: ['id', 'firstName', 'lastName'],
subQuery: false,
include: [
{
model: Friendships,
as: 'friendship',
attributes: ['userId', 'friendUserId'],
where:
{
[Op.or]: {
userId: userId,
friendUserId: userId
},
[Op.and]: {
friendshipStatusId: 'ACCEPT'
}
},
include: [{
model: UserPost,
as: 'user-post',
attributes: ['userId', 'postId'],
subQuery: false,
include: [
{
model: Post,
as: 'post',
attributes:['id','post'],
}
],
}]
}
] })
But in this query I am not getting users post records since there is
one entry in database of user post. following is actual result for
above query.
Response
[
{
"id": 5,
"firstName": "Abc",
"lastName": "Xyz",
"friendship": [
{
"userId": 5,
"friendUserId": 6,
"user-post": null
}
]
}
]
do anyone having solution for this?
Just to make sure we're on the same page, from features perspective you want users to be able to be friends with each others and posts created by a user can only be seen by that user and his friend.
From the relations perspective by UserPost you want to get all the users who have access to a post.
If this is correct then the way to go about it is much simpler.
First you don't need a many-to-many relation between user and post(UserPost) since you don't need many users to belong to a post unless a post can have multiple creators.
From raw database tables perspective we want(minimal):
User:
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| firstName | varchar(20) | YES | | NULL | |
| lastName | varchar(20) | YES | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
Friendship:
+-----------+-------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------------------------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| status | enum('PENDING','ACCEPTED','DENIED') | NO | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
| user_1 | int | YES | MUL | NULL | |
| user_2 | int | YES | MUL | NULL | |
+-----------+-------------------------------------+------+-----+---------+----------------+
Post:
+-----------+--------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| content | varchar(1000) | NO | | NULL | |
| status | enum('ACTIVE','DELETED') | NO | | NULL | |
| createdAt | datetime | NO | | NULL | |
| updatedAt | datetime | NO | | NULL | |
| UserId | int | YES | MUL | NULL | |
+-----------+--------------------------+------+-----+---------+----------------+
Which in sequelize can be done with:
const User = sequelize.define('User',{
firstName: {
type: DataTypes.STRING(20),
allowNull: true,
},
lastName: {
type: DataTypes.STRING(20),
allowNull: true,
}
})
User.associate = models => {
User.hasMany(models.Friendship, { foreignKey: "user_1" });
User.hasMany(models.Friendship, { foreignKey: "user_2" });
};
const Post = sequelize.define('Post',{
content: {
type: DataTypes.STRING(1000),
allowNull: false,
},
status: {
type: DataTypes.ENUM("ACTIVE", "DELETED"),
allowNull: false,
default: "ACTIVE"
}
}
);
Post.associate = models => {
Post.belongsTo(models.User);
};
const Friendship = sequelize.define('Friendship', {
status: {
type: DataTypes.ENUM("PENDING", "ACCEPTED", "DENIED"),
allowNull: false,
default: "PENDING"
}
});
Usage:
const models = require("./models")
const { Op } = require("sequelize");
const { User, Friendship, Post } = models;
const requestPost = async (user_id,post_id) => {
let user = await User.findOne({ where: { id: user_id } })
let post = await Post.findOne({ where: { id: post_id }, include: [User] })
let isFriend = await Friendship.findOne({
where: {
[Op.or]: [
{
user_1: user.id,
user_2: post.User.id,
status: "ACCEPTED"
},
{
user_1: post.User.id,
user_2: user.id,
status: "ACCEPTED"
}
]
}
})
if (isFriend) return post;
}
let run = async () => {
await models.sequelize.sync({ force: true });
let user1 = await User.create({
firstName: "dummy1",
lastName: "dummy1"
})
let user2 = await User.create({
firstName: "dummy2",
lastName: "dummy2"
})
let user3 = await User.create({
firstName: "dummy3",
lastName: "dummy3"
})
let user1_user2_friendship_accepted = await Friendship.create({
user_1: user1.id,
user_2: user2.id,
status: "ACCEPTED"
})
let user1_user3_friendship_pending = await Friendship.create({
user_1: user1.id,
user_2: user3.id,
})
let user1_post = await Post.create({
UserId: user1.id,
content: "Dummy-content"
})
// Example 1:
// user2 wants to access user1_post:
let getPost1 = await requestPost(user2.id, user1_post.id) // returns post
// Example 2:
// user3 wants to access user1_post:
let getPost2 = await requestPost(user3.id, user1_post.id) // returns undefined
console.log("\n\n\n\n")
if (getPost1) console.log("Returned getPost1")
if (getPost2) console.log("Returned getPost2")
}
run()
I have two Sequelize models that are associated with a belongsTo relationship. I would like to create an instance of user_sources when user is created but I am struggling to accomplish it.
model_user:
const User = sequelize.define('user', {
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
password: {
type: Sequelize.STRING,
allowNull: false
}
}, {
tableName: 'users'
})
model_user_sources:
const UserSources = sequelize.define('user_sources', {
abcNews: {
type: Sequelize.BOOLEAN,
},
bbcNews: {
type: Sequelize.BOOLEAN,
}
}, {
tableName: 'user_sources'
})
UserSources.belongsTo(User)
Both models are initialized and the tables are created in the database properly. According to the Sequelize documentation I should be able to create both with association in a single query like so:
User
.create({
email: user.email,
password: user.password,
}, {
include: UserSources
})
However, only the user is created. The user_sources item does not get created in the table.
Unfortunately the documentation only shows an example of creating a parent model from a child model but not the other way around. I have tried several different methods such as using a hasOne association, adding model/association options into the include, putting data into the create method, etc. But I feel as though I am not grasping the concept properly.
Would appreciate if someone could shed some light on my problem. Thanks.
"sequelize": "^5.21.3". Here are three ways to create data records for User and UserSources model with associations. Besides, we keep adding the foreign key constraint using userId to user_sources table.
E.g.
index.js:
import { sequelize } from '../../db';
import Sequelize from 'sequelize';
const User = sequelize.define(
'user',
{
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
},
{
tableName: 'users',
},
);
const UserSources = sequelize.define(
'user_source',
{
abcNews: {
type: Sequelize.BOOLEAN,
},
bbcNews: {
type: Sequelize.BOOLEAN,
},
},
{
tableName: 'user_sources',
},
);
UserSources.belongsTo(User);
// User.UserSources = User.hasOne(UserSources);
// User.hasOne(UserSources);
(async function test() {
try {
await sequelize.sync({ force: true });
// 1. User.UserSources = User.hasOne(UserSources);
// await User.create(
// {
// email: 'example#gmail.com',
// password: '123',
// user_source: {
// abcNews: true,
// bbcNews: true,
// },
// },
// {
// include: [
// {
// association: User.UserSources,
// },
// ],
// },
// );
// 2. User.hasOne(UserSources);
// await User.create(
// {
// email: 'example#gmail.com',
// password: '123',
// user_source: {
// abcNews: true,
// bbcNews: true,
// },
// },
// {
// include: [UserSources],
// },
// );
// 3. UserSources.belongsTo(User);
await UserSources.create(
{
abcNews: true,
bbcNews: true,
user: {
email: 'example#gmail.com',
password: '123',
},
},
{
include: [User],
},
);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
After executing the above code, check the data records in the database:
node-sequelize-examples=# select * from "users";
id | email | password
----+-------------------+----------
1 | example#gmail.com | 123
(1 row)
node-sequelize-examples=# select * from "user_sources";
id | abcNews | bbcNews | userId
----+---------+---------+--------
1 | t | t | 1
(1 row)
The data records are created as expected.
I have 3 models. User, Item and Location.
User.hasMany(Item)
Location.hasMany(Item)
Item.belongsTo(User)
Item.belongsTo(Location)
this runs, but does not create the location foreign key nor location row in locations table.
models.User.create(
{
username: 'ddavids',
email: 'hello#david.com',
password: '12345678',
items: [
{
itemName: 'Good Book',
orderDate: '2020-01-20',
locations: { locationName: 'floor' }
},
{
itemName: 'Bad Book',
orderDate: '2020-01-21',
locations: { locationName: 'shelf' }
}
]
},
{
include: [{ model: models.Item, include: [models.Location] }]
}
)
This creates the items and locations correctly but obviously not under a user.
models.Location.create(
{
locationName: 'floor',
items: [
{
itemName: 'Good Book',
orderDate: '2020-01-20',
locations: { locationName: 'floor' }
},
{
itemName: 'Bad Book',
orderDate: '2020-01-21',
locations: { locationName: 'shelf' }
}
]
},
{ include: [models.Item] }
)
What I can't figure out is if my relations are the wrong way to go about this or if its a limitation of create and I should move on or what.
My end goal will be something along the lines of.
User.hasMany(Order)
Order.belongsTo(User)
Order.hasMany(Item)
Item.belongsTo(Order)
Location.hasMany(Item)
Item.belongsTo(location)
Supplier.hasMany(Item)
Item.belongsTo(Supplier)
I am currently using create just to create some fake data for when I make changes. So if there is a better way to seed the database that would be my end goal.
Because of the association of Location and Item models is one-to-many. So you should change the
locations: { locationName: 'floor' } to location: { locationName: 'floor' }. The location of Item should not be plural. It means each item belongs to one location.
Here is the working example:
index.ts:
import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
class User extends Model {}
User.init(
{
username: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
},
{ sequelize, modelName: 'user' },
);
class Location extends Model {}
Location.init(
{
locationName: DataTypes.STRING,
},
{ sequelize, modelName: 'location' },
);
class Item extends Model {}
Item.init(
{
itemName: DataTypes.STRING,
orderDate: DataTypes.STRING,
},
{ sequelize, modelName: 'item' },
);
User.hasMany(Item);
Location.hasMany(Item);
Item.belongsTo(User);
Item.belongsTo(Location);
(async function test() {
try {
await sequelize.sync({ force: true });
await User.create(
{
username: 'ddavids',
email: 'hello#david.com',
password: '12345678',
items: [
{
itemName: 'Good Book',
orderDate: '2020-01-20',
location: { locationName: 'floor' },
},
{
itemName: 'Bad Book',
orderDate: '2020-01-21',
location: { locationName: 'shelf' },
},
],
},
{
include: [{ model: Item, include: [Location] }],
},
);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
After execution above code, check the data records in the database:
node-sequelize-examples=# select * from "user";
id | username | email | password
----+----------+-----------------+----------
1 | ddavids | hello#david.com | 12345678
(1 row)
node-sequelize-examples=# select * from "location";
id | locationName
----+--------------
1 | floor
2 | shelf
(2 rows)
node-sequelize-examples=# select * from "item";
id | itemName | orderDate | userId | locationId
----+-----------+------------+--------+------------
1 | Good Book | 2020-01-20 | 1 | 1
2 | Bad Book | 2020-01-21 | 1 | 2
(2 rows)
Data records inserted as expected.
sequelize version: "sequelize": "^5.21.3",
Source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/59937776
Goal
Using Sequelize and Postgres, I am trying to create a Readings table which contains values and their units. The units are foreign keys to another table, Units. I am confused with the associations.
Assumptions
Each Reading must have a sun value/unit and a moon value/unit.
The reading units can be different
Example Database
Readings
id | sun_temp | sun_temp_unit_id | moon_temp | moon_temp_unit_id
1 5 1 2 2
2 10 1 4 2
Units
id | Name
1 brapple
2 schmeckle
Readings Table Definition
const Reading = sequelize.define("Reading", {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
sun_temp: DataTypes.INTEGER,
moon_temp: DataTypes.INTEGER
}, {
timestamps: false,
tableName: "readings"
});
Reading.associate = (models) => {
Reading.belongsTo(models.Unit, {foreignKey: {name: 'sun_temp_unit_id'})
Reading.belongsTo(models.Unit, {foreignKey: {name: 'moon_temp_unit_id'})
}
Units Table Definition
const Unit = sequelize.define("Unit", {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: DataTypes.STRING
}, {
timestamps: false,
tableName: "units"
});
Unit.associate = (models) => {
??
}
Questions:
What type of an associate is this?
How do I set up the Reading model?
How do I set up the Unit model?
What query is used to get the Reading Model and the Units models? (Here I would like to see/access each Units name for reading value/unit pair)
If this is a poor way to set up the database, what are other suggestions?
//table main_lookup
const main_lookup=DB.connection.define('main_lookup',{
main_lookup_name: {
type :Sequelize.STRING,
primaryKey: true,
allowNull: false
},
value:{
type:Sequelize.JSON,
allowNull:false,
}
});
//table 2
const school_lookup= DB.connection.define('school_lookup',{
school_id : {
type :Sequelize.STRING,
allowNull: false,
references: {
model: schools,
key: 'school_id'
}
},
lookup_name: {
type :Sequelize.STRING,
unique: true,
allowNull: false
},
value: {
type: Sequelize.JSON,
allowNull: false,
}
});
i need to send data from main_lookup table to school lookup data
school_id // that is given by me
lookup_name // that is copy from main_lookup
value // that is copy from main_look_up
example
main lookup // table1
main_lookup_name value
---------------- -----
language ['english','tamil']
subject ['social','maths']
the solution is similar to the content following this
school_lookup // table2 //needed
school_id lookup value
--------- ------ -----
cit language ['english','tamil']
cit subject ['social','maths']
i need help in sequelize with simple ways
You can use raw query to do the same.
var Sequelize = require('sequelize');
var sequelize = new Sequelize('database', 'username', 'password');
sequelize.query("insert into <table1> select * from <table2>", {
type:Sequelize.QueryTypes.SELECT
}).then(function(results) {
console.log(results) // or do whatever you want
})
I think you are using sequelize like how people use microsoft excel or microsoft access. You can simply make relation in sequelize.
here is the code
//school-model
const School=Sequelize.define('school',{
name: {
type :Sequelize.STRING,
allowNull: false
}
});
//subject
const Subject= Sequelize.define('subject',{
type: {
type :Sequelize.STRING,
unique: true,
allowNull: false
},
value: {
type: Sequelize.ARRAY,
allowNull: false,
}
});
//database
const School = require('./path_to_schoolmodel');
const Subject = require('./path_to_subjectmodel');
Subject.belongsTo(School);
School.hasMany(Subject);
School model
id name
-- ---------------------
1 'fullstack academy'
2 'app academy'
Subject model
id type value schoolID
-- --------- -------------------- ------------------
1 language ['english','tamil'] 2
2 subject ['social','maths'] 1
if you setup model relationship you should be able to see you data like this.
Then when you use Sequelize model querying on your server side.
const School = require('./path_to_schoolmodel');
const Subject = require('./path_to_subjectmodel');
School.findAll({
include:[ Subject ]
})
.then(console.log)
.catch(console.error)
your console.log should return something like
[
{
id: 1,
name: 'fullstack academy'
subjects: [{
id: 2,
type: 'subject',
value: [
'socials', 'maths'
]
}]
},
{
id: 2,
name: 'app academy'
subjects: [{
id: 1,
type: 'language',
value: [
'english', 'tamil'
]
}]
},
]