This question already has answers here:
PostgreSQL "Column does not exist" but it actually does
(6 answers)
sql statement error: "column .. does not exist"
(1 answer)
Postgresql Column Not Found, But Shows in Describe
(1 answer)
Closed 2 years ago.
I have a problem.
SELECT *
FROM posts CROSS JOIN public."postReactions" AS reactions
WHERE posts.userId = '423abb9e-a00d-4045-9e88-4a85897f67e4'
But the response from DB is like 'ERROR: column posts.userid doesn't exist.
LINE 3: WHERE posts.userId = '423abb9e-a00d-4045-9e88-4a85897f67e4'.
Result of CROSS JOIN below:
Posts table
PostReactions table
Sequelize models below:
export default models => {
const {
User,
Post,
PostReaction,
PostNegativeReaction,
Comment,
Image
} = models;
User.hasMany(Post);
User.hasMany(PostReaction);
Post.belongsTo(User);
Post.hasMany(PostReaction);
PostReaction.belongsTo(Post);
PostReaction.belongsTo(User);
};
This is my associations:
export default {
up: (queryInterface, Sequelize) => queryInterface.sequelize
.transaction(transaction => Promise.all([
queryInterface.addColumn('posts', 'userId', {
type: Sequelize.UUID,
references: {
model: 'users',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
}, { transaction }),
queryInterface.addColumn('postReactions', 'userId', {
type: Sequelize.UUID,
references: {
model: 'users',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
}, { transaction }),
queryInterface.addColumn('postReactions', 'postId', {
type: Sequelize.UUID,
references: {
model: 'posts',
key: 'id'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
}, { transaction }),
])),
down: queryInterface => queryInterface.sequelize
.transaction(transaction => Promise.all([
queryInterface.removeColumn('posts', 'userId', { transaction }),
queryInterface.removeColumn('postReactions', 'userId', { transaction }),
queryInterface.removeColumn('postReactions', 'postId', { transaction })
]))
};
MERN stack.
Main problem: how to do a request to db that will receive the response with POSTS body (only liked by the current user).
This would be possible if the table were created using escaped column names . . . "postId" rather than postId.
I suspect that is the problem. The best solution is to recreate the table and not escape any identifiers, ever. Alternatively, you can use the escaped column name.
Related
I Have this postgres RAW query, I wanted to write it in Sequelize. How do I do this since I have less idea about Writing queries having JOINS in Sequelize. I have made models and Associations.
These are models and associations.
TestParticipant.hasMany(ParticipantHistory, {
sourceKey: "id",
foreignKey: "participantId",
as: "paticipantStatuses"
})
ParticipantHistory.belongsTo(TestParticipant, {
foreignKey: "participantId",
as: "paticipantStatuses"
})
This is the raw Query I wanna transform into Sequelize query
SELECT participant_histories.participant_id,
participant_histories.created_at,participant_histories.previous_status,
participant_histories.status,test_participants.test_type_id,test_participants.id,
test_participants.email,test_participants.scheduled_at,test_participants.valid_till,
test_participants.is_proctored
FROM test_participants
INNER JOIN participant_histories ON test_participants.id=participant_histories.participant_id
WHERE user_id='${userId}'
AND participant_histories.status='${activity}'
AND participant_histories.created_at>='${isoDate}'
Because I don't see model definitions in the post I suggest only something like this:
// First of all you should correct an alias for TestParticipant like this
ParticipantHistory.belongsTo(TestParticipant, {
foreignKey: "participantId",
as: "paticipant"
})
const rows = await ParticipantHistory.findAll({
raw: true,
attributes: ['participant_id', 'created_at', 'previous_status', 'status'],
where: {
status: activity,
created_at: {
[Op.gte]: isoDate
}
},
include: [{
required: true // this turns into INNER JOIN
model: TestParticipant,
attributes: ['test_type_id', 'id', 'email', 'scheduled_at', 'valid_till', 'is_proctored'],
as: 'participant',
where: {
user_id: userId
}
}]
})
I want to get objects from table providing id, which is in relation with table, which is in another relation. It looks like this:
Hand is in relation manyToOne with Action (hand can have only one action),
Action is in relation manyToOne with Situation (action can have only one situation)
I'm trying to make GET request for hands in which I'm providing situationId.
Simplified entities:
#Entity()
export class Hand {
#PrimaryGeneratedColumn()
hand_id: number;
#Column()
hand: string;
#ManyToOne(type => Action, action => action.simplifiedhands, { eager: true, onDelete: 'CASCADE', onUpdate: 'CASCADE' })
action: Action;
}
#Entity()
export class Action {
#PrimaryColumn()
action_id: number;
#ManyToOne(type => Situation, situation => situation.actions, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
#JoinColumn({name: 'situation'})
situation: Situation;
#OneToMany(type => Hand, hand => hand.action)
hands: Hand[];
#OneToMany(type => Hand, hand => hand.action)
hands: Hand[];
}
#Entity()
export class Situation {
#PrimaryColumn()
situation_id: number;
#ManyToOne(type => Strategy, strategy => strategy.situations, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
strategy: Strategy;
#OneToMany(type => Action, action => action.situation)
actions: Action[];
}
What approaches didn't work for me so far (just example variants):
return await this.handsRepository.find({
relations: ["action", "action.situation"],
where: {
"situation": id
}
});
and
return await this.handsRepository.find({
join: {
alias: "hands",
leftJoinAndSelect: {
"action": "hand.action",
"situation": "action.situation"
}
},
where: {
"situation": id
}
});
Generally both 'works' but provide all the records, like there were no where condition.
The keys in the object you assign to where should be members of the entity of the repository, in your case Hand, since situation is a member of action it's not working. I'm surprised you didn't mention any errors.
You can do one of the following (example for postgres)
Using query builder:
return await this.handsRepository.createQueryBuilder(Hand, 'hand')
.leftJoin('hand.action', 'action')
.leftJoin('action.situation', 'situation')
.where('situation.id = :id', { id })
.getMany();
Or, you can try the following (success is not guaranteed):
return await this.handsRepository.find({
relations: ["action", "action.situation"],
where: {
action: {
situation: { id }
}
}
});
I'm attempting to set up my User GraphQL model to have followers and following attributes to query on. However I'm having trouble setting up the relationship in Sequelize. I'm trying to use a Follower model as a Join Table and setup a BelongsToMany association, but haven't been able to get it working. Can anyone suggest what to do or point out what I'm doing wrong?
I've come up with a temporary solution by manually querying, which you can see in my User.model.ts, but I believe there is a better way to do it using proper configuration.
I'm using typescript wrappers around GraphQL and Sequelize, TypeGraphQL and sequelize-typescript respectively, as well as PostgreSQL.
User.model.ts
// VENDOR
import { ObjectType, Field, ID } from 'type-graphql';
import { Model, Table, Column, PrimaryKey, Unique, IsUUID, HasMany, DefaultScope, AllowNull, DataType, BelongsToMany } from 'sequelize-typescript';
// APP
import Post from '../post/post.types';
import Follower from '../follower/follower.types';
/** User model for GraphQL & Database */
#Table({ timestamps: false, tableName: 'users' }) // tell sequelize to treat class as table model
#DefaultScope(() => ({ include: [{ model: Post.scope(), as: 'posts' }] })) // tell sequelize to include posts in its default queries
#ObjectType() // tell GraphQL to treat class as GraphQL model
export default class User extends Model<User>{
#PrimaryKey
#Unique
#AllowNull(false)
#IsUUID(4)
#Column(DataType.UUID)
#Field(() => ID)
id: string;
#Unique
#AllowNull(false)
#Column
#Field()
ci_username: string;
#AllowNull(false)
#Column
#Field()
username: string;
#AllowNull(false)
#Column
#Field()
first_name: string;
#Column
#Field()
last_name: string;
#Column
#Field({ nullable: true })
profile_picture?: string;
// #BelongsToMany(() => User, { otherKey: 'user_id', as: 'followers', through: () => Follower })
// #Field(() => [User])
// followers: User[];
// MY TEMPORARY SOLUTION USING MANUAL QUERYING
#Field(() => [User])
get followers(): Promise<User[]> {
return Follower.findAll({ where: { user_id: this.id } })
.then(records => records.map(record => record.follower_id))
.then((follower_ids: string[]) => {
return User.findAll({ where: { id: follower_ids }});
})
}
// DOES NOT WORK, BUT I BELIEVE COULD POTENTIALLY LEAD TO BETTER SOLUTION
#BelongsToMany(() => User, { otherKey: 'follower_id', as: 'following', through: () => Follower })
#Field(() => [User])
following: User[];
#HasMany(() => Post)
#Field(() => [Post])
posts: Post[];
}
Follower.model.ts
// VENDOR
import { Model, Table, Column, PrimaryKey, Unique, IsUUID, AllowNull, DataType, Index, ForeignKey, AutoIncrement } from 'sequelize-typescript';
// APP
import User from '../user/user.types';
/** Follower model for Database */
#Table({ timestamps: false, tableName: 'followers' }) // tell sequelize to treat class as table model
export default class Follower extends Model<Follower>{
#PrimaryKey
#AutoIncrement
#Unique
#AllowNull(false)
#Column
id: number;
#AllowNull(false)
#IsUUID(4)
#Index
#ForeignKey(() => User)
#Column(DataType.UUID)
user_id: string;
#AllowNull(false)
#IsUUID(4)
#Index
#ForeignKey(() => User)
#Column(DataType.UUID)
follower_id: string;
}
GraphQL Query
{
users: allUsers {
id
username
first_name
last_name
following {
username
id
}
}
}
GraphQL Response / Error
{
"errors": [
{
"message": "Cannot return null for non-nullable field User.following.",
"locations": [
{
"line": 7,
"column": 5
}
],
"path": [
"users",
0,
"following"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Cannot return null for non-nullable field User.following.",
" at completeValue (/Users/jsainz237/Projects/trueview/trueview-api/node_modules/graphql/execution/execute.js:560:13)",
" at /Users/jsainz237/Projects/trueview/trueview-api/node_modules/graphql/execution/execute.js:492:16"
]
}
}
}
],
"data": null
}
Any help is appreciated.
You need to write a #FieldResolver manually that will resolve the relation and return proper data.
Another solution is to rely on ORM capabilities and lazy relations - when the returned base entity contains a promise as a field, so when .then() is called, it automatically fetches the relation for the database.
I am using sequelize(5.21.6) with sqlite3(^4.1.1).
I have two models A and B with many to many relation between them.
I want to bulk insert or update into the pivot table.
To achieve this I created a third model for the pivot table, lets call it AB.
So here is how I am trying to bulk upsert into pivot table.
db.AB.bulkCreate([array of values], {
updateOnDuplicate: ['aId', 'bId', 'updatedAt']
});
The error which I get:
{ Error: SQLITE_ERROR: near ")": syntax error
[0] errno: 1,
[0] code: 'SQLITE_ERROR',
[0] sql: INSERT INTO `AB` (`id`,`aId`,`bId`,`createdAt`,`updatedAt`) VALUES (19,1,1,'example',\'2020-04-15 15:18:59.000 +00:00\',\'2030-04-15 15:18:59.000 +00:00\'),(20,2,2,\'2030-04-15 15:19:49.000 +00:00\',\'2030-04-15 15:19:49.000 +00:00\') ON CONFLICT () DO UPDATE SET `aId`=EXCLUDED.`aId`, `bId`=EXCLUDED.`bId`,`updatedAt`=EXCLUDED.`updatedAt`;'
}
My AB model definition:
'use strict';
module.exports = (sequelize, DataTypes) => {
const AB = sequelize.define('AB', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true
},
aId: DataTypes.INTEGER,
bId: DataTypes.INTEGER
}, {});
AB.associate = function (models) {
// associations can be defined here
AB.belongsTo(models.A, { foreignKey: 'aId' });
AB.belongsTo(models.B, { foreignKey: 'bId' });
};
return AB;
};
I have a many to many relationship between: Step and Control Through ControlsConfig.
When creating a Control object and call addStep function and specify the additional attributes (which exist in the relation table), Sequelize creates the records in the relational table ControlsConfig but the additional attributes are NULLs.
PS: The tables are creating correctly in the database.
Table 1: Step
Table 2: Control
Relation table: ControlsConfig
Step
var Step = sequelize.define('Step', {
title: { type: DataTypes.STRING, allowNull: false },
description: DataTypes.STRING,
type: { type: DataTypes.ENUM('task', 'approval'), allowNull: false, defaultValue: 'task' },
order: DataTypes.INTEGER
});
Step.associate = function(models) {
models.Step.belongsTo(models.User);
models.Step.belongsTo(models.Template);
models.Step.hasMany(models.Action);
};
Control
var Control = sequelize.define('Control', {
label: { type: DataTypes.STRING, allowNull: false },
order: { type: DataTypes.INTEGER },
type: { type: DataTypes.ENUM('text', 'yes/no') },
config: { type: DataTypes.TEXT },
controlUiId: { type: DataTypes.STRING }
});
Control.associate = function(models) {
models.Control.belongsTo(models.Section);
};
ControlsConfigs
module.exports = (sequelize, DataTypes) => {
var ControlsConfig = sequelize.define('ControlsConfig', {
visibility: { type: DataTypes.ENUM('hidden', 'readonly', 'editable', 'required') },
config: { type: DataTypes.TEXT }
});
ControlsConfig.associate = function(models) {
models.Control.belongsToMany(models.Step, { through: models.ControlsConfig });
models.Step.belongsToMany(models.Control, { through: models.ControlsConfig });
models.ControlsConfig.belongsTo(models.Template);
};
return ControlsConfig;
};
Insertion:
try {
var step1 = await Step.create({ /*bla bla*/ });
var control1 = await Control.create({ /*bla bla*/ });
var OK = await control1.addStep(step1, {through: { config: 'THIS FIELD ALWAYS APPEARS NULL' }});
} catch (error) { /* No errors*/ }
I am following the same strategy stated at the documentation
//If you want additional attributes in your join table, you can define a model for the join table in sequelize, before you define the association, and then tell sequelize that it should use that model for joining, instead of creating a new one:
const User = sequelize.define('user', {})
const Project = sequelize.define('project', {})
const UserProjects = sequelize.define('userProjects', {
status: DataTypes.STRING
})
User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })
//To add a new project to a user and set its status, you pass extra options.through to the setter, which contains the attributes for the join table
user.addProject(project, { through: { status: 'started' }})
You have to pass edit: true to the addProject and addStep method.
See this answer it has a similar issue
Sequelize belongsToMany additional attributes in join table