Flutter
GraphQL
Relational Mutations
22 min
store relational data using graphql introduction in the last two tutorials we have performed graphql queries and mutations on a back4app database from our flutter app project we’re using graphql flutter https //pub dev/packages/graphql flutter/install as our graphql client once this is a very robust and far used project for those tutorials we’ve used a very simple data model with the most common types for our classes back4app is a flexible platform which allows you to create, store and query relational data in this tutorial we’re going to give a dive deep into this capability by showing you how to use relations and pointers when saving and querying relational data on back4app backend also, we are going to explore other data types that back4app offers like geopointer and datetime goals at the end of this article you’ll be able to create/update and delete relational data (using pointers and relations) create/update geopointers create/update date time prerequisites to complete this tutorial, you will need make sure you have read the previous two guides start from template and graphql mutation download the project file from github repo which includes the previous code as well as the new gui you would need open the downloaded project on a flutter ide like vs code or android studio back4app account that can be created here connect your tutorial to back4app as per the previous tutorials start from template 1 setting up back end on our previous project https //www back4app com/docs/flutter/flutter crud app example our data model was very simple with just a single class language now we’re going to make it more complex by adding 2 new classes and relating them to language founder with format column name description name name of the founder of the language column name description name name of owner company date owned date ownership gained by company headquarters headquarters location of the company we will create a one to one relation between class language and class founder using parse pointers, which will tell the founder of the specific language then, we create will one to many relation between class language and class ownership using parse relations that will tell which organisation/company owned the language, their headquarters and the date they acquired the ownership of the language the data model will look like that before we move to our app let’s create the classes and data in our back end that we would require go to your back4app app and then go to the graphql playground using the mutation below, create a class founder where we will store the language’s founders names 1 mutation createclass { 2 createclass(input { 3 name "founder" 4 schemafields { 5 addstrings \[{name "name"}] 6 } 7 }){ 8 class{ 9 schemafields{ 10 name 11 typename 12 } 13 } 14 } 15 } now let’s populate our class with some founder’s names in the following steps we will use this data to create new languages pointing to founder’s class use the mutation below on back4app graphql playground to create your founders 1 mutation createobject{ 2 createfounder(input {fields {name "james gosling"}}){ 3 founder{ 4 id 5 name 6 } 7 } 8 } here we have entered the java programming language founder’s name you can similarly for others too but right now this is enough for our guide let’s create the ownership class where we will store the language ownership, foundation date (date time) and the owner’s headquarter’s location (geopointer) later we will create the relation between the language class and ownership proceed by running the code below for creating the class 1 mutation createclass { 2 createclass(input { 3 name "ownership" 4 schemafields { 5 addstrings \[{name "name"}] 6 adddates \[{name "date owned"}] 7 } 8 }){ 9 class{ 10 schemafields{ 11 name 12 typename 13 } 14 } 15 } 16 } now populate the ownership class using the following mutations 1 mutation createobject{ 2 createownership(input {fields {name "sun microsystems"}}){ 3 ownership{ 4 id 5 name 6 } 7 } 8 } 1 mutation createobject{ 2 createownership(input {fields {name "oracle"}}){ 3 ownership{ 4 id 5 name 6 } 7 } 8 } now refresh the page, go to ownership ownership class on database browser select the add new column from the top right select geopoint from the first drop down and name it headquarters in the second text field and leave everything as it is and press the add column button then go to your language language class on database browser let’s add the relations to ownership ownership and founder founder classes click over add new column and then choose the data type pointer and the target class founder founder give the column the same name founder then press add column now repeat that process by adding a new column called ownership using the data type relation and selecting the class ownership ownership now you have your data model ready to use on your flutter app and to start saving and updating the data 2 creating/adding and deleting pointers now you need to download the project boilerplate code from our github repo https //github com/templates back4app/flutter graphql/tree/complex mutations open on your ide to connect your project to back4app go to the graphql playground and open then copy the keys and the api url as shown on the image below now paste them into the constants dart constants dart and run your project run the application in your emulator got to the m floating button on the bottom that will take us to the page where we performed simple mutations here you will find an extra floating action button cm that is hte button we’re going to use to perform our complex graphql mutations click on the cm button, and you will see another four buttons one for each operation we’re going to make on this guide now open the databaseutils dart databaseutils dart file and scroll down to the addpointers() addpointers() method here we will add the logic for adding pointers we are going to point james gosling as a founder of java language so first you will need to proceed to your back4app backend and copy both founder’s (james gosling) and language (java) objectid objectid updating/creating pointer to data proceed to our app inside the databaseutils dart databaseutils dart and inside the addpointers() addpointers() method initialize a string addpointerquery string addpointerquery where we will assign the graphql query for adding pointers as follows 1 string addpointerquery= 2 ''' 3 mutation addpointer(\\$languageid id!, \\$founderid updatelanguagefieldsinput! ){ 4 updatelanguage(input {id \\$languageid, fields \\$founderid}) 5 { 6 language{ 7 objectid 8 } 9 } 10 } 11 '''; and initialize final variable final variable to assign variables, notice we are taking the rowobjectid rowobjectid and pointersid pointersid as parameters where rowobjectid rowobjectid the object id of row from where we will point pointersid pointersid the object id to the row to be pointed so declare variable variable as 1 final variable={ 2 "userid" rowobjectid, 3 "founderid" { 4 "founder" { 5 "link" pointersid 6 } 7 } 8 }; now like the last guide we will initialize the graphqlclient graphqlclient and send query with the help of queryoptions() queryoptions() and return its instance with queryresults() queryresults() 1 graphqlconfiguration configuration = graphqlconfiguration(); 2 graphqlclient client = configuration clienttoquery(); 3 4 queryresult queryresult = await client query( 5 queryoptions(documentnode gql(addpointerquery), variables variable), 6 ); 7 return queryresult; this is how your addpointers() addpointers() method should look like 1 future\<queryresult> addpointers(string rowobjectid, string pointersid) async{ 2 print('addpointers'); 3 //code for add/update pointers 4 string addpointerquery= 5 ''' 6 mutation addpointer(\\$languageid id!, \\$founderid updatelanguagefieldsinput! ){ 7 updatelanguage(input {id \\$languageid, fields \\$founderid}) 8 { 9 language{ 10 objectid 11 } 12 } 13 } 14 '''; 15 final variable={ 16 "userid" rowobjectid, 17 "founderid" { 18 "founder" { 19 "link" pointersid 20 } 21 } 22 }; 23 graphqlconfiguration configuration = graphqlconfiguration(); 24 graphqlclient client = configuration clienttoquery(); 25 26 queryresult queryresult = await client query( 27 queryoptions(documentnode gql(addpointerquery), variables variable), 28 ); 29 return queryresult; 30 } hot restart your app now, go to the cm button on the mutation page and then press the set add pointers button here enter the row objectid objectid where the pointer needs to be added in the first text field and objectid objectid of row where it would point in the second text field and then press done now check your dashboard and you must be able to see a relation under the founder column you could click on it where it would take you to the row pointing to the founder class deleting pointer to data now proceed to the method deletepointers() deletepointers() where we will write logic to delete relations to delete relations you just have to make minor changes to the query above, that is, in the variables just change the "link" "link" with "remove" "remove" so after initializing final variable final variable it would be 1 final variable={ 2 "languageid" rowobjectid, 3 "founderid" { 4 "founder" { 5 "remove" pointersid 6 } 7 } 8 }; everything else will look exactly the same as the addpointers() addpointers() so your deletepointers() deletepointers() method looks like 1 future\<queryresult> deletepointers(string rowobjectid, string pointersid) async{ 2 print('deletepointers'); 3 //code for delete pointers 4 string removepointersquery= 5 ''' 6 mutation addpointer(\\$languageid id!, \\$founderid updatelanguagefieldsinput! ){ 7 updatelanguage(input {id \\$languageid, fields \\$founderid}) 8 { 9 language{ 10 objectid 11 } 12 } 13 } 14 '''; 15 final variable={ 16 "languageid" rowobjectid, 17 "founderid" { 18 "founder" { 19 "remove" pointersid 20 } 21 } 22 }; 23 graphqlconfiguration configuration = graphqlconfiguration(); 24 graphqlclient client = configuration clienttoquery(); 25 26 queryresult queryresult = await client query( 27 queryoptions(documentnode gql(removepointersquery), variables variable), 28 ); 29 return queryresult; 30 31 } you could now proceed to your back4app dashboard and see that the founder column of the specific row was deleted 3 creating/adding and deleting date time data if you remember we have created a class ownership ealier in step 1 and stored some data into it these are names of companies that owned java programing language so first let’s enter the dates the acuired the ownership let’s proceed to databaseutils dart databaseutils dart and create or scroll down to adddatetime() adddatetime() function here we will write logic to add data time datatype to our class initialize string adddatetimequery string adddatetimequery and assign it the query for creating date time data 1 string adddatetimequery= 2 ''' 3 mutation addtime(\\$rowid id!,\\$dateowned date!){ 4 updateownership(input {id \\$rowid, fields {date owned \\$dateowned}}) 5 { 6 ownership{ 7 objectid 8 } 9 } 10 } 11 '''; and the final variable final variable as 1 final variable={ 2 "rowid" rowobjectid, 3 "dateowned" datetime 4 }; now initialize the graphqlclient graphqlclient and pass the query throught the queryoption() queryoption() this is how your function would look like 1 future\<queryresult> adddatetime(string rowobjectid, string datetime) async{ 2 print('adddatetime'); 3 //code for add/update date time 4 string adddatetimequery= 5 ''' 6 mutation addtime(\\$rowid id!,\\$dateowned date!){ 7 updateownership(input {id \\$rowid, fields {date owned \\$dateowned}}) 8 { 9 ownership{ 10 objectid 11 } 12 } 13 } 14 '''; 15 final variable={ 16 "rowid" rowobjectid, 17 "dateowned" datetime 18 }; 19 graphqlconfiguration configuration = graphqlconfiguration(); 20 graphqlclient client = configuration clienttoquery(); 21 queryresult queryresult = await client query( 22 queryoptions(documentnode gql(adddatetimequery), variables variable), 23 ); 24 return queryresult; 25 } now hot restart application and note down the objectid of row containing sun microsystems in name column press the add date time button now enter the objectid noted in the first text field and “02 24 1982” as mm dd yyyy format at the day when java was pubished and press the done button proceed to your back4app backend and you would date in form of 24 feb 1982 at 00 00 00 utc which means it has identified the datatype as date time datatype similarly, you could add “01 27 2010” for the date owned for oracle 4 adding/updating geopointer data let’s add geopointer data to locate head quateres of of the comapnies from the ownership table proceed to database utils dart database utils dart file and scroll down to addgeopointers() addgeopointers() function now initialize string addgeopointers string addgeopointers and assign the respective query 1 string addgeopointers= 2 ''' 3 mutation addgeopointer(\\$objectid id!,\\$latitude float!,\\$longitude float!){ 4 updateownership(input {id \\$objectid, fields { headquarters {latitude \\$latitude, longitude \\$longitude}}}) 5 { 6 ownership{ 7 objectid 8 } 9 } 10 } 11 '''; and final variable final variable as 1 final variable={ 2 "objectid" rowobjectid, 3 "latitude" double parse(latitude), 4 "longitude" double parse(longitude), 5 }; since latitude latitude and longitude longitude are double values we need to parse them from string to double before sending it initialise the grapqlclient grapqlclient and pass query with by queryoption() queryoption() this is how your addgeopointers() addgeopointers() function would look like 1 future\<queryresult> addgeopointers(string rowobjectid, string latitude, string longitude) async{ 2 print('add geopointers'); 3 //code for add/update geopointers 4 string addgeopointers= 5 ''' 6 mutation addgeopointer(\\$objectid id!,\\$latitude float!,\\$longitude float!){ 7 updateownership(input {id \\$objectid, fields { headquarters {latitude \\$latitude, longitude \\$longitude}}}) 8 { 9 ownership{ 10 objectid 11 } 12 } 13 } 14 '''; 15 final variable={ 16 "objectid" rowobjectid, 17 "latitude" double parse(latitude), 18 "longitude" double parse(longitude), 19 }; 20 graphqlconfiguration configuration = graphqlconfiguration(); 21 graphqlclient client = configuration clienttoquery(); 22 queryresult queryresult = await client query( 23 queryoptions(documentnode gql(addgeopointers), variables variable), 24 ); 25 return queryresult; 26 } hot restart your app and select the add geopointers button enter 37 35 37 35 in the first text box and 121 95 121 95 in the second text box enter the objectid of the row with sun microsystems as name and press done now proceed to your back4app backend and you would see (37 35, 121 95) which are co ordinates of the headquaters and states that it identifies it as geopointers 5 adding/updating and deleting relation in pointers we can nly point to one row, but with the help of relations we can make connection to multiple rows so lets make relation of our language table to these two rows for ownership of the java language adding/updating relation proceed to database utils dart database utils dart file and proceed to addrelation() addrelation() function for writing the logic initialize string addrelationquery string addrelationquery and assign the query for relation as follows 1 string addrelationquery= 2 ''' 3 mutation addrelation(\\$objectid id!, \\$relationid ownershiprelationinput){ 4 updatelanguage(input {id \\$objectid, fields {ownership \\$relationid}}) 5 { 6 language{ 7 objectid 8 } 9 } 10 } 11 '''; and the final variable final variable would be 1 final variable= { 2 "objectid" objectid, 3 "relationid" relationid 4 }; so after initializing the graphqlclient graphqlclient and passing the query like before this is how your database utils dart database utils dart would look like 1 future\<queryresult> addrelation(string rowobjectid, string relationid) async{ 2 //code for add/update relation 3 print('addrelation'); 4 string addrelationquery= 5 ''' 6 mutation addrelation(\\$objectid id!, \\$relationid ownershiprelationinput){ 7 updatelanguage(input {id \\$objectid, fields {ownership \\$relationid}}) 8 { 9 language{ 10 objectid 11 } 12 } 13 } 14 '''; 15 final variable= { 16 "objectid" rowobjectid, 17 "relationid" { 18 "add" relationid 19 } 20 }; 21 graphqlconfiguration configuration = graphqlconfiguration(); 22 graphqlclient client = configuration clienttoquery(); 23 queryresult queryresult = await client query( 24 queryoptions(documentnode gql(addrelationquery), variables variable), 25 ); 26 print(queryresult); 27 return queryresult; 28 } success your app has finally stored relational, datetime and geopointers data on back4app! conclusion in this guide we learned how to store relational data on back4app using graphql form a flutter app project also we worked with other graphql mutations like geopointers and datetime, creating, updating and deleting data on the next tutorial we are going to deep dive into queries to our flutter app this guide was written by asim junain, from hybrowlabs https //www back4app com/partners/software development company