apollo-client icon indicating copy to clipboard operation
apollo-client copied to clipboard

Weird Merging of Duplicate Array

Open yj7 opened this issue 3 years ago • 9 comments
trafficstars

For a given query which responds something like this ->

{
    foo
    {
        
        bar {
            c [{a}]
        }
    }
    bar
    {
        c[{b,c,a,d}]
    }
}

Intended outcome:

the intended outcome is either a union of the two or replace one with other -> c = [{a}] or c = [{b,c,a,d}]

Actual outcome:

the response object will contain c as [{a,c,a,d}] -> merge of the two instances with values being replaced

How to reproduce the issue:

Versions

System: OS: macOS 13.0.1 Binaries: Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node Yarn: 1.22.19 - ~/.nvm/versions/node/v16.14.2/bin/yarn npm: 8.5.0 - ~/.nvm/versions/node/v16.14.2/bin/npm Browsers: Chrome: 107.0.5304.110 Safari: 16.1 npmPackages: @apollo/client: 3.6.2 => 3.6.2 apollo-server-core: ^3.9.0 => 3.11.1 apollo-server-express: 3.9.0 => 3.9.0

yj7 avatar Nov 19 '22 05:11 yj7

Hey @yj7! Thanks for opening the issue. Have you looked at our docs regarding cache field behavior? From what I understand, you may need to tweak the default merge strategy used to ensure the fields are properly written to the cache.

If you've got type/field policies defined that are setup as you expect and you believe this is a bug, would you be willing to get us a reproduction of the issue to better figure out what might be happening here? Thanks!

jerelmiller avatar Nov 21 '22 17:11 jerelmiller

Hey @jerelmiller -> Here is the reproduction. https://github.com/yj7/apollo-bug-repo.

Trying to explain the issue again with the example repo as reference.

query AllPeople {
    user{
      id,
      name,
      fruits{
        id,
        name
      }
    }
    people {
      id
      name
      fruits{
        id
        name
      }
    }
  }

This is the query being fired -> User object will always return details about Sara Smith -> with the fruits array containing 3 items

{ id: 1, name: 'apple', },
{ id: 2, name: 'mango', },
{ id: 3, name: 'banana', }

The people query will return an array of Persons including Sara Smith. In this query the fruits array will return only 1 fruit banana.

Since Sara Smith is returned twice as part of the same response with 2 different fruits array. Apollo Merges the two array and gives a mixed array.

Actual Output

{ id: 3, name: 'banana', },
{ id: 2, name: 'mango', },
{ id: 3, name: 'banana', }

Expected Output

{ id: 1, name: 'apple', },
{ id: 2, name: 'mango', },
{ id: 3, name: 'banana', }

Or

{ id: 3, name: 'banana', }

Also another observation -> the order of the query affects the result / output. If the query is changed to

people {
      id
      name
      fruits{
        id
        name
      }
    }
    user{
      id,
      name,
      fruits{
        id,
        name
      }
    }
Result for Sara Smith ->  Fruits is 
{ id: 1, name: 'apple', },
{ id: 2, name: 'mango', },
{ id: 3, name: 'banana', }

yj7 avatar Nov 27 '22 10:11 yj7

Hi @yj7 👋🏻 can you help me understand these lines?

https://github.com/yj7/apollo-bug-repo/blob/148b69c5510e703447d0ba829636153c25849e72/src/schema.js#L32-L37

bignimbus avatar Dec 08 '22 19:12 bignimbus

@bignimbus That is just a hack for this reproduction. The effect i am trying to achieve is -> based on the query the fruits object can have a list of all items or a subset of the items.

Imagine it as when querying people we only send the favourite fruit but when querying user we send all the fruits.

yj7 avatar Dec 09 '22 08:12 yj7

Thanks @yj7, we'll take a closer look at your reproduction as soon as we can. As @jerelmiller noted, type and field policies exist so the developer can control how to handle updates of list types. Did defining a policy help address the issue you saw in your application?

bignimbus avatar Dec 09 '22 19:12 bignimbus

@bignimbus Defining a policy did not help ... was getting the incorrect merged array in the update cache function. What helped was changing the order of the query.

yj7 avatar Dec 10 '22 16:12 yj7

@bignimbus Any update on this?

yj7 avatar Jan 16 '23 16:01 yj7

I have encountered same issue Node.js v21.5.0 npm 10.2.4 OS: macOS 14.0 Firefox 121.0 (64-bit) @apollo/client 3.8.8

Server (rust) juniper 0.15.11

HTTP requests come with correct payload. This happens only when cache is involved

Code to reproduce:

  • back end on rust https://gitlab.com/yar.ua/dictionary-service-be/-/tree/54439693beac9d2dd45f1a8cf433f7e7d7a29c23
  • front end https://gitlab.com/yar.ua/dictionary-service-fe/-/tree/b38bd61e8753a233b9d9708c5a416ffcdd2e4728 Steps: On the page click on the first item in the left column (view should load), then click on the second item in the left column (another set of data should load), finally click again on the first item (now the content is mix of both items)

Teivaz avatar Jan 03 '24 20:01 Teivaz

We faced a similar issue. I'll replace our model names with generic examples. In our case we had an array of Person which contained an array of Pet.

If PersonA had Dog in Pet and if PersonB also had Dog in Pet, then PersonB's Dog would become the same as PersonA's. Our Dog object would share the same id but had different attributes like name, but the name and other attributes from PersonA's Dog was being used in PersonB's Dog.

In our case, we renamed id to dogId and it worked as expected. So I think there is some weird behaviour with Apollo and id for the same model being used in different contexts.

I'm not exactly sure if this is the same issue as the original, but thought I would share it in case it helps anyone

joingram-priceline avatar Apr 05 '24 16:04 joingram-priceline