Why doesn't using GraphQL `connect` on a 1-1 relationship connect both ways but only one way?

I have the following mutation:

const CREATE_CANVAS = gql`
  mutation CREATE_CANVAS($userId: ID!, $projectId: ID!){
    createdCanvas: createCanvas(data: {
      id: ""
      owner: {
        connect: $userId
      }
      project: {
        connect: $projectId
      }
    }){
      ...canvasFields
    }
  }
  ${canvas.canvasFields}
`;

It creates the following project:

{
  "ref": Ref(Collection("Projects"), "294406582593126919"),
  "ts": 1617026846950000,
  "data": {
    "id": "",
    "label": "test",
    "owner": Ref(Collection("Users"), "293673586012455429"),
    "canvas": Ref(Collection("Canvas"), "294406583103783431")
  }
}

And the following canvas:

{
  "ref": Ref(Collection("Canvas"), "294406583103783431"),
  "ts": 1617026846950000,
  "data": {
    "id": "",
    "owner": Ref(Collection("Users"), "293673586012455429")
  }
}

Why doesn’t the canvas document has a project field? It only linked half of it, although the project doc does have the expected project relation.


Here is my schema:

type Project @collection(
    name: "Projects"
){
    id: ID!
    """
    Name of the project
    """
    label: String!
    owner: User! @relation(
        name: "userProjects"
    )
    canvas: Canvas @relation(
        name: "projectCanvas"
    )
}

type Canvas @collection(
    name: "Canvas"
){
    id: ID!
    lastUpdatedBySessionEphemeralId: String
    lastUpdatedByUserName: String
    project: Project! @relation(
        name: "projectCanvas"
    )
    owner: User! @relation(
        name: "userCanvases"
    )
}

It does have a two way connection. But it is fulfilled through an index.

Fauna can model the relationship directly this way, so there is no reason to duplicate the data in both collections. Specifying the one-to-one relation in GraphQL will automatically generate the required index.

Check out the docs on Relations. Indeed check all the docs out! :slight_smile: But this is an important one to see how Fauna actually models the relationships based on the schema you upload.

traversing the relations would work something like the following.

From Project to Canvas:

Let(
  {
    projectRef: Ref(Collection("Projects"), "294406582593126919")
    projectDoc: Get(Var('projectRef'))
    canvasRef: Select(['data', 'canvas'], Var('projectDoc'))
  },
  Get(Var('canvasRef'))
)

From Canvas to Project:

Let(
  {
    canvasRef: Ref(Collection("Canvas"), "294406583103783431")
  },
  Get(Match(Index('canvas_project_by_canvas'), Var('canvasRef'))
)

You can do all of this in FQL yourself. Check out this gist as well if you are interested in more complex nested FQL queries, and how relations can be a part of them.

1 Like

Okay! Thanks for the explanation! I knew about indexes and read the doc intensely, but it didn’t occur to me it’d automatically use the index in such a way to avoid storing a duplicata of the data, it’s smart.