How can I edit the data in a table with GraphQL

I looked at the tutorials for how to edit data with sql using bulkupdate. I don’t know how to do that using graphql as the query-language. We have a query that allows to edit a single entry, not bulk. How can a user edit a table-entry and after he did that we call the graphql-query with the data that was just changed.

This should be very simple.
I have a mutation update_entry(key: String!, value: String!) How can I hook up retool to call this one on the last changed table-row.

If a different container like the key-value-map would be easier I can also use that, altough I have yet to find a way to make that one editable.

Hey @Noz! The basic structure is that you’ll want to create a Run JS Code query that loops through each updated row in your table, and triggers that update_entry mutation for each. I wrote up a basic guide for how to do this with Firestore in our docs here. It kind of looks like this:

const toUpdate = table.recordUpdates
toUpdate.forEach((record) => {
  updateDocument.trigger()
})

In your case, you might want to pass different data into your mutation each time (looks like you have variables for key and value). To do that, you can use the additionalScope parameter in Retool’s query.trigger() method:

const toUpdate = table.recordUpdates
toUpdate.forEach((record) => {
  updateDocument.trigger({
    additionalScope: {
      document_id: record._id,
      document_object: record
    }
  })
})

Note that when you reference those variables in your mutation query (e.g. document_id), you’ll get an error in the editor - that’s fine, it’s because these variables get defined at runtime.

LMK if this helps! The .recordUpdates is an array of objects which can be a bit confusing at first.

I tried this js-query:

const toUpdate = table1.recordUpdates
toUpdate.forEach((record) => {
  update_entry.trigger({
    additionalScope: {
    	key: record.key,
      value: record.value,
    }
  })
})

Now when I run this as the bulk-query for table1 I get a warning:
update_entry: Variable "$key" of required type "String!" was not provided.
And nothing gets saved.
I logged the record and it looks correct e. g. I changed three entries and it is an array of three objects, who all have the expected keys and values.

edit:
I changed the order of variables in my mutation. Before it was like this:

mutation ($key: String!, $value: String!){
  internal_set_stuff(key: $key, value: $value)
}

now I tried this

mutation ( $value: String!, $key: String!){
  internal_set_stuff(key: $key, value: $value)
}

When I run it now it says
update_entry: Variable "$value" of required type "String!" was not provided.
So I assume this

update_entry.trigger({
    additionalScope: {
    	key: record.key,
      value: record.value,
    }
  })

is not working and no variable is actually getting from the js-query to the graphql-mutation, at least not in the way i expect it to.

Any idea why my version is not working?

@Noz what does your mutation query look like? Are you referencing variables with {{}}?

Okay thanks. Referencing the variables with {{}} works.

1 Like

@Noz @justin can you share the graphQL mutation and the JS script you used? I’m stuck on the same issue and I’m new to both Retool and graphQL. Appreciate your help!

@zcoop321
Try to pass variables with the additionalScope parameter from a JS script to the GraphQL query as mentioned by @justin .

You can then reference these variables inside your GraphQL query by enclosing them in double curved brackets (e.g. {{record_id}}). This will give you an error message in the editor but it works.

For string values, I also had to put quotes around the variables, resulting in something like this (using BaseQL to update an Airtable record in this case):

mutation {
  update_issue(
    id: "{{record_id}}",
    description: "{{description}}",
  ) {
    id,
    description
  }
}
1 Like

My bulk_update looks like this:

const toUpdate = table1.recordUpdates
toUpdate.forEach((record) => {
  console.log(record);
  update_entry.trigger({
    additionalScope: {
      value: record.value,
      key: record.key
    }
  });
});

And the graphql-query belonging to this looks like this:


What still isn't obvious to me is where exactly the scopes overlap. By putting stuff in the additionalScope, they are available in the Variables-field. Why? I don't know. I don't know enough about retools scoping mechanism.

Hey Noz! When you trigger a query and pass in additionalScope, you are simply making those variables available in the scope of the triggered query. Certain resource types will have the variables field and you can find them there. Others don't but you can still access them with {{ variableName }}, or simply variableName, depending on the query type. Generally this functionality is used when you have variables that are NOT defined on your app's global scope and therefore are not available to that query otherwise. As a very simple example of showing the availability of these variables I have attached a couple of screenshots.




Here we have access to foo in query2 (once query1 is run) even though query2 would otherwise have no possible way of accessing that variable. Hope this helps clear some things up!