-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to avoid Dup Records when executing Create Mutation Commits that Insert New Edges into Connections #1734
Comments
I had a similar problem and setup. I was able to resolve the issue by pulling the 'node' out of my edge, creating a new edge with
Not entirely sure why it didn't work before, but seems to work when I create the new edge. I think the issue could be related to my variables not changing between mutation commits? |
Thanks for reporting this. It's a known issue where mutations with the same variables end up having the same ids for some records (those that don't have their own |
@josephsavona I this need to create my own updater and cannot relay on |
Hey, I solved this by removing RANGE_ADD on configs, it's either you choose from updater or RANGE_ADD |
use updater or config tks |
…or each executed mutation (#2349) Summary: Fixes #1734 Fixes #2333 Related to relayjs/relay-examples#30 When a mutation is executed, it's payload is added to the store using a key of the serialized arguments. In the Todo Modern example this looks like this: ```js { 'client:root:addTodo(input:{"text":"a"})': { ... } // added by mutation response 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:root:addTodo(input:{"text":"a"}):todoEdge', // added by mutation imperative updater function ] ] } } ``` If you execute a second `addTodo` mutation with the same arguments, the `client:root:addTodo(input:{"text":"a"})` field in the store will get overwritten with the second mutation and the store will look like this: ```js { 'client:root:addTodo(input:{"text":"a"})': { ... } 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:root:addTodo(input:{"text":"a"}):todoEdge', 'client:root:addTodo(input:{"text":"a"}):todoEdge', ] ] } } ``` When React renders the data, you will have the latter `todo` in the connection array twice and will likely get an error along the lines of `Encountered two children with the same key, <id>. Child keys must be unique; when two children share a key, only the first child will be used`. This was [fixed in relay-examples](relayjs/relay-examples@ed95594#diff-4b42725e6eb503f56da8e3f637e9a4e3) by adding a `clientMutationId` to the mutation arguments. I don't think this is ideal since 1. it requires the developer to manually add this to each mutation 2. it places an additional constraint on the GraphQL schema to support this field. The approach I took to fix this, was to use a new root `dataID` (instead of the static `client:root`) for results on each mutation. This will namespace results from each mutation so they can never overwrite one another. With these changes, the relay store now looks like this after completing the same series of mutations: ```js { 'client:mutationRoot0:addTodo(input:{"text":"a"})': { ... }, 'client:mutationRoot1:addTodo(input:{"text":"a"})': { ... }, 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:mutationRoot0:addTodo(input:{"text":"a"}):todoEdge', 'client:mutationRoot1:addTodo(input:{"text":"a"}):todoEdge' ] ] } } ``` I tested this and it works to solve this issue, but I'm unsure if there could be any unintended consequences by this change. Closes #2349 Reviewed By: josephsavona Differential Revision: D7631345 Pulled By: tyao1 fbshipit-source-id: fc53638536860855f271f436f810caa0fc60bcb0
…or each executed mutation (#2349) Summary: Fixes #1734 Fixes #2333 Related to relayjs/relay-examples#30 When a mutation is executed, it's payload is added to the store using a key of the serialized arguments. In the Todo Modern example this looks like this: ```js { 'client:root:addTodo(input:{"text":"a"})': { ... } // added by mutation response 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:root:addTodo(input:{"text":"a"}):todoEdge', // added by mutation imperative updater function ] ] } } ``` If you execute a second `addTodo` mutation with the same arguments, the `client:root:addTodo(input:{"text":"a"})` field in the store will get overwritten with the second mutation and the store will look like this: ```js { 'client:root:addTodo(input:{"text":"a"})': { ... } 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:root:addTodo(input:{"text":"a"}):todoEdge', 'client:root:addTodo(input:{"text":"a"}):todoEdge', ] ] } } ``` When React renders the data, you will have the latter `todo` in the connection array twice and will likely get an error along the lines of `Encountered two children with the same key, <id>. Child keys must be unique; when two children share a key, only the first child will be used`. This was [fixed in relay-examples](relayjs/relay-examples@ed95594#diff-4b42725e6eb503f56da8e3f637e9a4e3) by adding a `clientMutationId` to the mutation arguments. I don't think this is ideal since 1. it requires the developer to manually add this to each mutation 2. it places an additional constraint on the GraphQL schema to support this field. The approach I took to fix this, was to use a new root `dataID` (instead of the static `client:root`) for results on each mutation. This will namespace results from each mutation so they can never overwrite one another. With these changes, the relay store now looks like this after completing the same series of mutations: ```js { 'client:mutationRoot0:addTodo(input:{"text":"a"})': { ... }, 'client:mutationRoot1:addTodo(input:{"text":"a"})': { ... }, 'client:VXNlcjptZQ==:__TodoList_todos_connection': { edges: [ __refs: [ 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:0', 'client:VXNlcjptZQ==:__TodoList_todos_connection:edges:1', 'client:mutationRoot0:addTodo(input:{"text":"a"}):todoEdge', 'client:mutationRoot1:addTodo(input:{"text":"a"}):todoEdge' ] ] } } ``` I tested this and it works to solve this issue, but I'm unsure if there could be any unintended consequences by this change. Closes #2349 Reviewed By: josephsavona Differential Revision: D7631345 Pulled By: tyao1 fbshipit-source-id: fc53638536860855f271f436f810caa0fc60bcb0
Having trouble implementing a simple Document Component that adds a document and updates a connection relation with Application.documents edges. The Create works fine, but the Updater keeps adding the LinkedRecord reference to the same Edge every time I run InsertEdgeAfter on the Application.documents Connection. This causes duplicate records since it keeps updating the old Edge records by reference. I'm hoping I don't have to destroy the Component to create a separate reference for the Create Edge LinkedRecord. How do we add multiple edges to Connections if we always receive the same referenced Edge?
Here is the mutation to create a document, it returns an associated Application.id as well as the expected edge.
Here is my updater method that gets the payload, finds the Edge, then uses the application proxy to get the Connection to insert the Edge into. The problem is the Edge is a linked record and every time I run a commit on this create it keeps updating the Edge reference and incrementing pointers to the latest Edge value.
My connection is simply just a list of the documents for this application. After I insert each document, the list starts creating duplicates simply because the references all point to the last Edge created. The GraphQL data storage is fine, but my local update is failing due to this issue.
Application.documents = [
11111, <- created in an earlier session
2222, <- created in an earlier session
12345, <- created in the current session
12345, <- created in the current session
12345, <- created in the current session, keeps repeating as I run the commit trigger
]
The text was updated successfully, but these errors were encountered: