[VERY_UNLIKELY] Fetch concrete references with graphql (and the other array fields?)

I have…

I’m submitting a…

  • [ ] Regression (a behavior that stopped working in a new release)
  • [x] Bug report
  • [ ] Performance issue
  • [ ] Documentation issue or request

Current behavior

I have two entites: Users and Teams connected with one another with extra information on the connection - role. Using graphql I can easily get the role a user has in each time as the teams field returns a UsersDataTeamsChildDto type which then has all the information from the link. However when traversing from teams to users using the referencingUsersContents the field returns an array of Users meaning its impossible to get the role.

Expected behavior

The return type of the referencingUsersContents should not be a User but a connection type (something like UsersDataTeamsChildDto except in reverse) so we would be able to get the information from the API

Minimal reproduction of the problem

see above

Environment

  • [ ] Self hosted with docker
  • [ ] Self hosted with IIS
  • [ ] Self hosted with other version
  • [x] Cloud version

Version: [VERSION]

Browser:

  • [ ] Chrome (desktop)
  • [ ] Chrome (Android)
  • [ ] Chrome (iOS)
  • [ ] Firefox
  • [ ] Safari (desktop)
  • [ ] Safari (iOS)
  • [ ] IE
  • [ ] Edge

Others:

This would only work if you would model relationships explicitly. But this is not possible right and will probably never work like that as it does not fit to the document-oriented approach. I am not sure how to implement your use case right now.

You have to do it manually by also also resolving the team id and role from your array field.

if there is a way to attach the data inside the relationship and the reverse reference is present in graphql surely the data should be accessible? May I ask why you think that the document-oriented approach is relevant? To be fair as a user I would expect the CMS to abstract the data-store layer away from the me anyway.

I would argue that the Squidex GraphQL layer was modelled incorrectly - the referencingXXXX property should not be returning the desired type directly and instead should return some sort of a Connection type that would then resolve to the desired one, much like in the opposite direction when does exactly that.

So let me sum it up:

Given the many-to-many relationship between a User and aTeam, where there can be data attached to the relationship (for instance - the role), this data can be returned from Squidex GraphQL in full:
User -> Team
but this can’t:
Team -> User
as the data from the relationship is not available.

Seems a little illogical, don’t you think?

The problem is that the reference does not know the context, in which it is used.

Lets say you have the following structure:

"team": {
   "name": "Adults",
   "players": [{
       "userId": "123"
       "role": "Keeper"
    }, {
       "userId": "456"
       "role": "Striker"
    }],
    "trainer": "789"
  }
}

and another team

"team": {
   "name": "Juniors",
   "players": [{
       "userId": "abc"
       "role": "Keeper"
    }, {
       "userId": "def"
       "role": "Striker"
    }],
    "trainer": "123"
  }
}

So user “123” is the trainer in keeper in team “Adults” and the trainer in team “Juniors”. How would you model this in GraphQL? The connection type in case 2 would not have any properties.

The fact that a reference is used inside an array does not mean that the other properties build a relationship.

I would model it exactly the same way you modelled it in in the opposite direction.

Perhaps I should also make it clear that in our schema a User has a Teams fields which of Array type and that Array then have a nested fields which are: role and team

Anyway - any many-to-many relationship can be represented in GraphQL in both directions, otherwise it would be a huge limitation to GraphQL.

In your example the query I would use to get the user and the teams they belong to (and its pretty much how you have it in Squidex):

query {
   user(id: "123") {
      teams {
         role
         team {
            name
         }
      }
   }
}

and to get the teams with users and their roles I would do:

query {
   team(id: "team juniors ID") {
      users {
         role
         user {
            id
            name
         }
      }
   }
}

which in squidex should look more like (and this is the important bit!):

findTeamsContent(id: "055038ee-8bed-4439-9985-69a1fbc9de9b") {
    id
    referencingUsersContents {
       role
       user {
          flatData {
             id
             name
          }
       }
    }
  }

You created another relationship which is a 1-1 relationship for the trainer which im not sure is relevant here, for all I know I am only interested in the players and the ability to traverse from users to teams and from teams to users and in each direction I would like to know their roles. It is currently only possible in one direction.

I don’t see how it can be currently implemented, because the reference does not know the context it belongs to. In my example above you would also get teams where the user is the trainer from the database and then you would have to filter out the cases where he is a player making things like pagination and so on impossible. You have to model a concrete connection to do that and store it in a totally different way.

I will think about it closed but it is a non-trivial issue.