How to retrieve users post using sequalize in express? - javascript

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()

Related

Updating a row in a Postgres table using Sequelize

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.

I'm trying to Include a has many association in findAll and i'm geting an error

I want to return the has many association from this model
module.exports = (sequelize, DataTypes) => {
const Message = sequelize.define('Message', {
title: DataTypes.STRING,
message: DataTypes.STRING,
userId: DataTypes.STRING,
teacherId: DataTypes.STRING,
}, {});
Message.associate = function(models) {
Message.belongsTo(models.User, {foreignKey: 'userId'});
Message.belongsTo(models.Teacher, {foreignKey: 'teacherId'});
Message.hasMany(models.Reply, {foreignKey: 'messageId'});
};
return Message;
}
the model i want to include
module.exports = (sequelize, DataTypes) => {
const Reply = sequelize.define('Reply', {
reply: DataTypes.STRING,
messageId: DataTypes.STRING,
}, {});
Reply.associate = function(models) {
Reply.belongsTo(models.Message, {foreignKey: 'messageId'});
};
return Reply;
}
i get an error every time i run this code.
getUserMessages(req, res){
const {userId} = req.params;
Message.findAll({include:[{model:"Reply"}],where: { userId }}).then((e) =>{
res.json(e);
}).catch((error) =>{
console.log(error);
})
},
the error i get when i try to access the controller
error: column Replies.teacherId does not exist
How can i include this model on my find all query?
It seems that your models don't have correct associations. Here is a working example:
index.ts:
import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
class User extends Model {}
User.init({}, { sequelize, modelName: 'users' });
class Teacher extends Model {}
Teacher.init({}, { sequelize, modelName: 'teachers' });
class Reply extends Model {}
Reply.init(
{
id: {
primaryKey: true,
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
},
},
{ sequelize, modelName: 'replies' },
);
class Message extends Model {}
Message.init(
{
title: DataTypes.STRING,
message: DataTypes.STRING,
userId: DataTypes.INTEGER,
teacherId: DataTypes.INTEGER,
},
{ sequelize, modelName: 'messages' },
);
const MessageBelongsToUser = Message.belongsTo(User, { foreignKey: 'userId' });
const MessageBelongsToTeacher = Message.belongsTo(Teacher, { foreignKey: 'teacherId' });
Message.hasMany(Reply, { foreignKey: 'messageId' });
Reply.belongsTo(Message, { foreignKey: 'messageId' });
(async function test() {
try {
await sequelize.sync({ force: true });
await Message.create(
{
title: 'messsage title',
message: 'message content',
user: {},
teacher: {},
replies: [{ id: 1 }, { id: 2 }],
},
{ include: [{ association: MessageBelongsToUser }, Reply, { association: MessageBelongsToTeacher }] },
);
const userId = 1;
const rval = await Message.findAll({ include: [{ model: Reply }], where: { userId }, raw: true });
console.log('rval: ', rval);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
The execution result of above code:
rval: [ { id: 1,
title: 'messsage title',
message: 'message content',
userId: 1,
teacherId: 1,
'replies.id': 1,
'replies.messageId': 1 },
{ id: 1,
title: 'messsage title',
message: 'message content',
userId: 1,
teacherId: 1,
'replies.id': 2,
'replies.messageId': 1 } ]
Check the data records in the database:
node-sequelize-examples=# select * from users;
id
----
1
(1 row)
node-sequelize-examples=# select * from replies;
id | messageId
----+-----------
1 | 1
2 | 1
(2 rows)
node-sequelize-examples=# select * from messages;
id | title | message | userId | teacherId
----+----------------+-----------------+--------+-----------
1 | messsage title | message content | 1 | 1
(1 row)
node-sequelize-examples=# select * from teachers;
id
----
1
source code: https://github.com/mrdulin/node-sequelize-examples/tree/master/src/examples/stackoverflow/60479744

How to use Sequelize create with nested objects and relations

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

How does Reflexive association work in SAILS JS?

Here is my User model: I am trying to create a reflexive association among users. Mentors and mentees
fullName: {
type: 'string',
required: true,
description: 'Full representation of the user\'s name',
maxLength: 120,
example: 'Lisa Microwave van der Jenny'
},
typeOfUser: {
required: true,
type: 'string',
example: 'mentor',
description: 'The user\'s type of account.',
},
skills:{
collection:'skills',
via: 'userId'
},
mentees:{
collection: 'user',
via: 'mentors'
},
mentors:{
collection:'user',
via: 'mentees'
}
Here is my code.
// Add mentor of mentorId as the mentor of currentUser
await User.addToCollection(3, 'mentor',8);
// Find mentor and populate mentees
var showMentee = await User.findOne(8).populate('mentee');
The Response is correct:
{
"mentee": [
{
"id": 3,
"fullName": "1234",
"typeOfUser": "mentee"
}
],
"id": 8,
"fullName": "1234",
"typeOfUser": "mentor"
}
But the problem is with the association table that sails has created:
+----+-------------+-------------+
| id | user_mentee | user_mentor |
+----+-------------+-------------+
| 1 | 8 | 3 |
| 2 | 8 | 3 |
+----+-------------+-------------+
I can not understand the column naming in this case. The mentor id is 8 and mentee id is 3, but it is showing opposite.

How to insert all values from another table using sequelize

//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'
]
}]
},
]

Categories