How can I update a graphql entry? - reactjs

I have a schema as follows:
type User #model {
id: ID!
firstName: String!
lastName: String!
locations: [Location]
}
type Location #model {
id: ID!
listOfPictures: [String]
address: String!
owner: User
}
Currently I have entries to both Locations and Users. The entries for my Locations are all null.
I want to update one of my Locations, of ID '1234' to have the field 'owner' set to the User of ID '5678'.
What is the correct syntax for this? What do I have to enter into he Appsync console?
Additionally, how could I update the 'locations' field of my User of id 'abc' model to add a Location, to the array of Locations, of Location with id 'def' ?
Thanks.

You can update your data by using mutations: https://docs.aws.amazon.com/appsync/latest/devguide/quickstart-write-queries.html

Related

How to create updating mutation with hasura for 2 related tables (for Recipe app)

Hello i am making recipe app and at this point i have to create editing functionality by getting update mutation from hasura.But i have issues trying to create this mutation.Because there are two tables related to each other, one of them is recipes and other related by id is ingredient which is a array of objects .I need to populate existing form with a dynamic ingredient field with existing recipe data and then to be able to edit that data .At first i thought i will be able to create something similar to what i did with insert mutation but inserting and updating have diferent properties and im abit lost here.
here is how i wrote my insertion mutation which is working fine
mutation insertRecipe(
$title: String!
$image: String!
$description: String!
$Date: date!
$ingredient_relation: [ingredient_insert_input!]!
) {
insert_recipes(
objects: {
title: $title
image: $image
description: $description
Date: $Date
ingredient_relation: { data: $ingredient_relation }
}
) {
returning {
id
}
}
}
and here is my atempt at updating mutation but update doesent have data property which i used in insert mutation
mutation recipe_edit(
$title: String!
$id: Int!
$image: String!
$description: String!
$Date: date!
$ingredient_relation: [ingredient_insert_input!]!
) {
update_recipes(
_set: {
title: $title
image: $image
description: $description
Date: $Date
}
where: { id: { _eq: $id } }
) {
returning {
id
}
}
update_ingredient(
_set: { data: $ingredient_relation }
where: { recipe_id: { _eq: $id } }
) {
returning {
id
}
}
}
I also made fully working updating withouth variables it works only in hasura graphiql interface
mutation UpdateRecipe {
update_recipes(_set: {title: "lets change title", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Vytautas_the_Great_Bridge_from_hill%2C_Kaunas%2C_Lithuania_-_Diliff.jpg/1280px-Vytautas_the_Great_Bridge_from_hill%2C_Kaunas%2C_Lithuania_-_Diliff.jpgs", description: "new description", Date: "1991-06-09"}, where: {id: {_eq: 10}}) {
affected_rows
}
update_ingredient(_set: {name: "lets change the name"}, where: {recipe_id: {_eq: 10}}) {
affected_rows
}
}
Unfortunately, you cannot update multiple records by ID in 1 mutation section.
There are 2 approaches I typically use for this issue.
1: use an insert mutation with an on_conflict constraint for the table ID and supply all columns you wish to update if they conflict to the update_columns parameter. You just declare a single variable of the [table]_insert_input type and pass in the updated record as a JS object (instead of passing in each value separately). You can nest child records here as well. You will need to declare conflict constraints and columns to update for the children as well. Messing around with the graphiql interface should help you figure out how to do this. This has the benefit of using the same query for both insert and update operations. It has the same downside as well... (permissions)
2: using code (presumably) you can generate as many update graphql sections as you'd like. Like so:
const MUTATION = `mutation UpdateRecipe {
update_recipes(_set: {title: "lets change title", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Vytautas_the_Great_Bridge_from_hill%2C_Kaunas%2C_Lithuania_-_Diliff.jpg/1280px-Vytautas_the_Great_Bridge_from_hill%2C_Kaunas%2C_Lithuania_-_Diliff.jpgs", description: "new description", Date: "1991-06-09"}, where: {id: {_eq: 10}}) {
affected_rows
}
${
ingredients.map((ingrd, i) => `
update_ingredient_${i}: update_ingredient(_set: {name: ${ingrd.name}}, where: {id: {_eq: ${ingrd.id}}}) {
returning { ... }
}
`).join("\n")
}
}`
Notice I prefixed each section because 1 query cannot have multiple sections of the same name.
While option 2 certainly feels "icky"er it has the single benefit of using the correct permission for the operation...
Hope this helps

How we can add custom fields to mongodb database?

Hello guys I need your help,
I am making a simple app where users can create a post about their favorite person so there are different fields to write text, now I've made the functionality for the user to create any new field with a title of their choice like if a person "a" want to add a new field with name age and custom "b" wants to add a new field with name country, so I've made this but how can I get that custom data automatically in my database so if the user will create a new field with any name I want that field and text written in it in my database. Can you help me with that?
and please try to explain to me in a simple manner am just a beginner with mongoDB.
there was a guy who told me to do this with $addFields aggregation but he didn't tell me anything else I saw many documents but am not getting How can I make this done :(
thank you sooooo much in advance. :)
here's my schema for default fields:
const personSchema = new Schema({
firstName: String,
lastName: String,
birthDay: String,
gender: String,
pronouns: String,
relationship: String,
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
username: String,
}
});
You simply have to pass the strict option to false while you create your schema!
By default, mongoose will set this option to true so you can't send any unnecessary information to DB!
const personSchema = new Schema({
firstName: String,
lastName: String,
birthDay: String,
gender: String,
pronouns: String,
relationship: String,
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
username: String,
}
}, { strict: false });
https://mongoosejs.com/docs/guide.html#strict

Joi validation - dynamic control on 3 fields

I'm dealing with 3 form fields in order to validate them. Here are the basic schema :
schema = {
firstName: JoiExtend.string().allow(''),
lastName: JoiExtend.string().allow(''),
birthDate: JoiExtend
.date().format("DD/MM/YYYY").utc()
.allow(null).allow('')
};
So the validation rules are :
If firstName is set with value, lastName must have a value
If lastName is set with value, firstName must have a value
If birthDate is set with value, firstName and lastName must have a value
I'm really struggling for doing this, I've started to work with this approach :
schema = {
firstName: JoiExtend.when('lastName', {
is: JoiExtend.string(),
then: JoiExtend.string().required(),
otherwise: JoiExtend.string().allow('')
}),
lastName: JoiExtend.when('firstName', {
is: JoiExtend.string(),
then: JoiExtend.string().required(),
otherwise: JoiExtend.string().allow('')
}),
dateNaissance: JoiExtend
.date().format("DD/MM/YYYY").utc()
.label("La Date de naissance")
.allow(null).allow('')
.messages(this.getErrorMessage())
};
But I have the following error : Uncaught Error: item added into group lastName created a dependencies error
Moreover, this code does not take into account the rule with birthDate
Any help ?

mongoose update only not nulled fields?

If I want to update already created collection, I want only save not null fields.
Example- Suppose I create a collection Here User-
name: "Siam Ahnaf"
password: "12345678"
role: "user"
This is created collection. Then I want to update it. For updating I get this object from frontend application like this-
{name: "",
password: "98765432"
role: "Admin"}
Here I can see name is empty that I get from frontend application. When I update it with
User.findByIdAndUpdate(req.user._id, {...input})
It update the collection with this empty name. After updating my collection is like this-
name: ""
password: "98765432"
role: "Admin"
But I want when name is empty then it will not save this empty valuse. It remain previous value. How can I do that?
You can remove empty string properties from the object before save it.
const obj = {
name: "",
password: "98765432",
role: "Admin"
}
Object.keys(obj).forEach((k) => obj[k] == '' && delete obj[k]);
User.findByIdAndUpdate(req.user._id, obj)
The remove empty string properties function is taken from https://stackoverflow.com/a/38340730/9095807
or use the .pre('save') method of mongoose like this: https://stackoverflow.com/a/59916058/9095807

Object Fields Missing in Autogenerated Mutation Input for GraphQL AppSync

I have a custom GraphQL schema for a blogging application for my ReactJS app. The main model type is Post.
Post contains a number of properties that have a custom type eg Gallery: [MediaObject]. The majority of these properties with custom types are missing from the automatically generated CreatePostInput by AWS Amplify CLI. This means that I cannot create a Post object that has these properties with custom type.
The lack of these custom type properties is evident in the AppSync console, under Queries. In the Explorer, go to Mutations, click on CreatePost mutation, and you will see that 6 of the 21 properties for Post are missing. The missing properties are tags, attributes, seo, featuredImage, gallery and createdBy.
They are also missing in the autogenerated graphql schema in api > build > schema.graphql in the react app.
I have made multiple clean projects from scratch, and the problem is reproducible. I have updated the amplify cli to 4.51.2 and still no luck.
I would expect the CreatePostInput to have the associated inputs for all of the fields, not just comments (see the autogenerated CreatePostInput below) eg: attribute: AttributeInput, but these are not generated either. This would allow me to create a Post object that has these custom fields populated. However, only the CommentInput has been generated. What am I doing wrong here, or have I misunderstood something?
Thanks!
Below is my gql schema and both the autogenerated CreatePostInput and CommentInput:
type Post #model {
id: ID
createdBy: User
createdAt: AWSDateTime
updatedAt:AWSDateTime
type: PostType!
title: String!
status: Status
content: String!
excerpt: String
slug: AWSURL
wordpressId: Int
wordpressImageURLs: [AWSURL]
author: String
likes: Int
tags: [Tag]
attributes: Attribute
seo: Seo
featuredImage: MediaObject
gallery: [MediaObject]
comments: [Comment]
numberOfComments: Int
}
type User #model {
id: ID
username: String!
firstName: String
lastName: String
email: AWSEmail!
avatar: MediaObject
location: String
createdAt: AWSDateTime
updatedAt: AWSDateTime
Posts: [Post]
}
type Tag #model {
id: ID
postIds: [ID]
name: String!
}
type Attribute #model {
id: ID
postId: ID
link: String
imgUrl: AWSURL
ogImage: AWSURL
ogDescription: String
canonicalLink: AWSURL
}
type Seo #model {
id: ID
postId: ID
metaRobotsNoIndex: String
metaRobotsNoFollow: String
canonical: AWSURL
metaDesc: String
opengraphDescription: String
opengraphModifiedTime: AWSDateTime
opengraphPublishedTime: AWSDateTime
opengraphTitle: String
opengraphUrl: AWSURL
opengraphImage: AWSURL
twitterDescription: String
twitterImage: String
twitterTitle: String
schemaSeo: String
}
type Comment
{
id: ID
postId: ID!
createdBy: ID
author: String
createdAt: AWSDateTime
text: String!
likes: Int
}
type MediaObject #model {
id: ID
linkedId: ID
createdBy: ID
mediaItemUrl: AWSURL
srcSet: String
medium: AWSURL
thumb: AWSURL
sourceURL: AWSURL
description: String
bucket: String
region: String
key: String
type: MediaObjectType
}
type Like #model {
id: ID!
objectVotedOnID: ID!
createdBy: ID
createdAt: AWSDateTime
likeOn: LikeOnType
}
enum PostType {
TOOLS
BLOGS
INSPIRATIONS
NEWS
POSTS
NEWSLETTERS
}
enum LikeOnType {
POST
COMMENT
}
enum Status {
PUBLISH
DRAFT
}
enum MediaObjectType {
IMAGE
VIDEO
AUDIO
}
Autogenerated (only CreatePostInput and CommentInput have been included for brevity), found in amplify > backend > api > build > schema.graphql:
input CreatePostInput {
id: ID
createdAt: AWSDateTime
updatedAt: AWSDateTime
type: PostType!
title: String!
status: Status
content: String!
excerpt: String
slug: AWSURL
wordpressId: Int
wordpressImageURLs: [AWSURL]
author: String
likes: Int
comments: [CommentInput]
numberOfComments: Int
}
input CommentInput {
id: ID
postId: ID!
createdBy: ID
author: String
createdAt: AWSDateTime
text: String!
likes: Int
}
At least for the example, you cited, Post and MediaObject have a one-to-many relationship. That is, a single Post has many MediaObjects. You won't see the many relations of a one-to-many generated on the parent object for mutations.
When creating a parent object that has children, you'll need to do this in 2 steps.
Create the parent object, and return the id.
Using the parentId, create the N child objects.
Here is some documentation from Amplify on how to do this: https://docs.amplify.aws/cli/graphql-transformer/connection#has-many
To anyone else that notices this strange behaviour: The reason why CommentInput is included in the CreatePostInput, whilst the other custom types are not, is because Comment was the only type that I had forgot to label with an #model directive. I assume that this means that AppSync then views this type on the comments field as a set of nested fields, rather than an object with its own DynamoDB table. I have asked the AWS Amplify team and will update this answer when I hear more from them.

Resources