Upsert Graphql Mutation with conflict constraint on nested object - graphql

I am trying to do an upsert in a single mutation. Here I have two tables Users table [id,isVerified,type] and Customers table [id,name,deviceToken] Here,Customers.id is a foreign key of Users.Id.
The following is the mutation-
MyMutation {
insert_Users(objects: [{isVerified: false, name: "+9100000000", type: "customer",
Customers: {data: {deviceToken: "TestToken001"}}}],
on_conflict: {
constraint: Users_name_key,
update_columns: [isVerified]
}) {
affected_rows
returning {
Customers{
deviceToken
}
}
}
} ```
//But when I run this, I get the exception
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_Users.args.objects[0].Customers.data",
"code": "constraint-violation"
},
"message": "Uniqueness violation. duplicate key value violates unique constraint \"Customers_pkey\""
}
]
}
This seems to be because I am not setting conflict constraint on the nested Customers Object. How do I add the conflict constraint for a nested object?

You need to add the constraint object inside the nested data as well.
Something like:
MyMutation {
insert_Users(objects: [{isVerified: false, name: "+9100000000", type: "customer",
Customers: {
data: {deviceToken: "TestToken001"},
on_conflict: {
constraint: Customers_pkey,
update_columns: [deviceToken]
}
}}],
on_conflict: {
constraint: Users_name_key,
update_columns: [isVerified]
}) {
affected_rows
returning {
Customers{
deviceToken
}
}
}
}

Related

Hasura GraphQL UPSERT mutation for nested objects

So I'm trying to construct a mutation for inserting/updating a record for a "Person" along with it's address, email, telephones information into multiple tables, using variables.
mutation insertPerson ($address: [adr_insert_input!]!, $emails: [emails_insert_input!]!) {
insert_info(objects: [{
f_name: "User1",
l_name: "Test"
address: {
data: $address,
on_conflict: {
constraint: person_id_pk,
update_column: [add_text_line1, zip_code]
}
},
emails: {
data: $emails,
on_conflict: {
constraint: person_id_pk,
update_column: [email_text]
}
}
}], on_conflict: {
constraints: person_pk,
update_columns: [f_name, l_name]
}) {
affected_rows
}
}
and my variables are set-up as follows...
{
"address": [{
"add_text_line1": "123 Main Street",
"zip_code": 50501
}],
"emails": [{
"email_text": "FirstLastName#email.com"
}]
}
This works as expected for me (with multiple values in emails array too), but I need to move the f_name & l_name values (whole Person object) into a variable as well. How do I achieve that?
I tried the below mutation this way, but this resulted into two separate inserts & empty values being passed...
mutation insertPerson ($person: person_insert_input!, $address: [adr_insert_input!]!){
insertData(objects: [
$person,
{
address: { data: $address }
}
]) { affected_rows }
}
This resulted to a two separate insertions... First person with empty address, then empty person with address.
How do I achieve the first mutation's result, while using Person Info as part of variables NOT hard-code it into the query itself?
Thank you!
You will need to pass the insert_info objects as the variables
mutation insertPerson ($info_objects: [insert_info_insert_input!]!) {
insert_info(objects: $info_objects, on_conflict: {
constraints: person_pk,
update_columns: [f_name, l_name]
}) {
affected_rows
}
}
And your variables will be an array of the info_objects
{info_objects: [{
f_name: "User1",
l_name: "Test"
address: {
data: [{
"add_text_line1": "123 Main Street",
"zip_code": 50501
}]
},
on_conflict: {
constraint: person_id_pk,
update_column: [add_text_line1, zip_code]
}
},
emails: {
data: [{
email_text: "FirstLastName#email.com"
}],
on_conflict: {
constraint: person_id_pk,
update_column: [email_text]
}
}
}]}

How to insert an object and related array objects in one mutation

I have two tables reels and reel_variations, reels can have many reel_variations and reel_variations belong to one reel. I have read the Hasura docs and haven't been able to figure out how to insert a reel and a couple of reel variations in a single mutation.
mutation insertReelsAndVariations($objects: [reels_insert_input!]! = {}) {
insert_reels(objects: $objects) {
affected_rows
returning {
description
id
name
variations {
ball_bearings
braid_capacity
created_at
deleted_at
gear_ratio
max_drag
line_capacity
id
model_number
recovery
reel_id
retrieve
}
}
}
}
Variables
{
"objects": {
"name": "nice reel",
"description": "wicked nice reel",
"variations": {
"data": {
"ball_bearings": "djjdfkjdkjfdjkfjkd",
"braid_capacity": "dkfjdkfjkdf",
"gear_ratio": "20:1",
"max_drag": "20lbs",
"line_capacity": "400yrds",
"model_number": "jfdkjfkjdkfjkdjfjdf",
"recovery": "30 per turn"
}
}
}
}
Errors
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_reels.args.objects[0].variations.data",
"code": "constraint-violation"
},
"message": "Not-NULL violation. null value in column \"reel_id\" violates not-null constraint"
}
]
}
That's because the reel_id column is not set as a foreign key col referencing the reels table. So u can simply:
Make the reel_id col a foreign key which points to the id column of reels table!

How to upsert nested tables values in Hasura GraphQL?

wanted to ask if it is possible to upsert nested objects? for example, if i have a 'Users' table and a 'Students' table, and I'm inserting a new User(with a taken id), i want to update all fields (using on_conflict and update_columns) including the fields in the 'Students' table.
Basically replace all user's fields except the primary key.
mutation($UsersData: [core_users_insert_input!]!) {
insert_core_users(
objects: $UsersData
on_conflict: {
constraint: core_users_id_unique
update_columns: [first_name, last_name, gender]
}
) {
affected_rows
}
}
The update_column array should include fields from the 'Students' table but i can't figure it out.
It is possible, relevant documentation is here: https://hasura.io/docs/1.0/graphql/manual/mutations/upsert.html#upsert-in-nested-mutations
It is possible to use on_conflict key on any level (top, or nested) where you want to resolve updating an existing record.
mutation upsert_author_article {
insert_author(
objects: [
{
name: "John",
articles: {
data: [
{
title: "Article 3",
content: "Article 3 content"
}
],
on_conflict: {
constraint: article_title_key,
update_columns: [content]
}
}
}
]
) {
affected_rows
}
}

How to build a many-to-many insert mutation in Hasura?

I am building my first many-to-many insert mutation in Hasura and finding it difficult. The syntax in the docs and the accompanying explanation is very difficult to follow.
I am simply trying to add a connection between a component and a module.
Here is the state of my current query.
mutation MyMutation {
insert_component(objects: {component_module: {data: {module: {data: {id: "775c9e27-c974-4cfa-a01f-af50bd742726"}, on_conflict: {constraint: module_id_key, update_columns: id}}}}}) {
affected_rows
returning {
id
component_modules
}
}
}
Here is the error I get.
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_component.args.objects[0].component_module.data",
"code": "constraint-violation"
},
"message": "Not-NULL violation. null value in column \"component_id\" violates not-null constraint"
}
]
}
Here is my component table
Here is my module table
Here is my component_module bridge table
Thanks in advance for your help.
Your mutation is not working because you are inserting the id manually and when Hasura generates the query it won't have the id in the parent.
When doing nested inserts the best is to let PostgreSQL generate the ids for you. This way you will be able to insert with either side of the relationship.
In your example you don't really need to have the component_modules column in each table. When doing many to many inserts you can use the id of each table as the foreign key.
For example:
component
- id
- created_at
- updated_at
- name
module
- id
- created_at
- updated_at
- name
component_module
- component_id
- module_id
And the mutation should be something like:
mutation {
insert_component(objects: {
name:"component name",
component_modules: {
data: {
module: {
data: {
name: "module name"
}
}
}
}
}) {
returning {
id
component_modules {
component {
name
}
}
}
}
}

Sequelize include with multiple where condition

I have a bit of problem for using Sequelize with include. The problem is that my model uses two primary keys in child table.
So it goes like this
Parent table
User : Id, ...
Post : Id, UserId(foreign key, binds to user id), ...
Post Hash Tag : HashTag, PostId(foreign key, binds to Post id), UserId(foreign key, binds to user id of Post table)
So the table hierarchy looks like this
user - post - post hash tag
Now when I try to do like this,
Post.findAll(
include: {
model: post hash tag
}
)
then it only searches the post hash tags for where post id of post hash tag table is equal to post id of post table
So I added like this
Post.findAll(
include: {
model: post hash tag
where: {
col1: models.sequelize.where(models.sequelize.col('POST.USER_ID'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
}
}
);
Then it will gives a problem at 'where' clause that Post.USER_ID cannot be found.
If I change col1 value to Post.userId then now it solves the above error but gives another error at 'on' clause
Do you have any idea how I can solve this?
The full model is given here
User
sequelize.define('User', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey : true }
)
Post - I know multiple primary declaration is not working correctly, so don't bother to consider too much
sequelize.define('Post', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
)
Post hash tag
sequelize.define('PostHashTag', {
postId: { type: DataTypes.STRING(6), field: 'POST_ID', primaryKey: true },
hashTag: { type: DataTypes.STRING(20), field: 'HASH_TAG', primaryKey: true },
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
}
)
and the query I used is
Post.findAll({
attributes: ['id', 'userId'],
where: {
userId: userId,
id: { $lt: postId }
},
include: [{
model: models.PostHashTag,
attributes: ['hashTag'],
where: {
col1: models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
}]).then(...)
I found an answer by myself... col1:
models.sequelize.where(models.sequelize.col('Post.USER_ID'), '=', models.sequelize.col('PostHashTag.userId'))
this should be
userId: models.sequelize.where(models.sequelize.col('POST.userId'), '=', models.sequelize.col('POST_HASH_TAG.USER_ID'))
this will work. The physical names of table and column used in parenthesis

Resources