question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Pairs of Relationship fields (ie. "backlinks") store 2 copies of relationship data; copies not kept in sync

See original GitHub issue

I have a Keystone, running on Knex/Postgres, using the latest packages (@keystonejs/keystone: 5.1.1, @keystonejs/adapter-knex: 5.1.0, @keystonejs/app-admin-ui: 5.0.2, @keystonejs/app-graphql: 5.0.0, @keystonejs/fields: 5.1.0).

It has two related lists:

keystone.createList('User', {
  fields: {
    name: { type: Text },
    posts: { type: Relationship, ref: 'Post.author', many: true },
    // ...
  },
});

keystone.createList('Post', {
  fields: {
    name: { type: Text },
    author: { type: Relationship, ref: 'User.posts' },
    // ...
  },
});

There’s a bunch of data in this system already. For example, the user 1747 is author of post ABCD. GraphQL bears this out:

{
  User(where: { id: "1747" }) {
    id
    name
    posts { id name }
  }
}

Which correctly returns:

{
  "data": {
    "User": {
      "id": "1747",
      "name": "Aida Yasuaki",
      "posts": [
        {
          "id": "ABCD",
          "name": "Soroban For Dummies"
        }
      ]
    }
  }
}

The Admin UI for this post gives me a drop down to select the single author (user). Updating the author to user 1598 performs a query like this:

mutation {
  updatePost(
   id: "ABCD"
   data: {
     author: { connect: { id: "1598" } }
   }
  ) { id __typename }
}

But when we look at the data we see now both users think they own the post:

{
  allUsers(where: { id_in: ["1747", "1598"] }) {
    id
    name
    posts { id name }
  }
}

Returns…

{
  "data": {
    "allUsers": [
      {
        "id": "1747",
        "name": "Aida Yasuaki",
        "posts": [{ "id": "ABCD", "name": "Soroban For Dummies" }]
      },
      {
        "id": "1598",
        "name": "Yoshida Mitsuyoshi",
        "posts": [{ "id": "ABCD", "name": "Soroban For Dummies" }]
      }
    ]
  }
}

So, the bug here is that the Admin UI isn’t including disconnectAll: true when setting many: false relationships. The GraphQL mutation above should be something like:

mutation {
  updatePost(
   id: "ABCD"
   data: {
     author: { disconnectAll: true, connect: { id: "1598" } }
   }
  ) { id __typename }
}

That specific issue shouldn’t be hard to fix but the real issue here is the concept of backlinks as a whole. We’re actually maintaining two separate relationships here: A one-to-many relationship and a separate many-to-many relationship linking the same tables. (Note that, when even when both authors think they “own” the post, the post itself links correctly to just one.)

I’ll write this larger issue separately but, sufficed to say, backlinks add complexity (surface area for bugs like this! ^^), slow down data access (reads and writes) and makes maintaining data integrity a lot harder. They’re also unnecessary 😃

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:9 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
timlesliecommented, Apr 7, 2020

Fixed in #2000

1reaction
molombycommented, Apr 20, 2020

Could this be solved by “pseudo backlinks”, meaning one side it is actually stored but the other side is computed using db queries in resolvers.

As above, it’s not possible to store “one side” of a relationship; you either store it or you don’t. If the link between two items is stored somewhere there’s nothing left to “compute”.

We need to get far away from “backlinks” as a concept. They simply don’t exist in any meaningful way. We want to be able to configure:

  • Links between lists
  • How these are exposed in GraphQL
  • How these are exposed in the Admin UI

There is no blessed/special/front/back side of a relationship in our conceptual model, regardless of where the config exists in the codebase.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Flexible Sync on links - Atlas Device Sync - MongoDB
I was wondering how to work with object-links and Flexible Sync. Considering one very simple example: @RealmModel() class _Pet { .
Read more >
Back links and link discovery - IBM
With back links, two artifacts are related to one another by a pair of links. Each artifact stores a link that points to...
Read more >
Automatic Bi-directional linking + Rollups / Transclusion
When you create a Relation like that there are actually two relations created that are synced or linked. If you add Object B...
Read more >
125 Unbelievable “Anchor Text” Backlinks! - MGS Logistics
NOTE: Remember to use only TWO anchor text keyword links at a time for each website below! You can make two profiles for...
Read more >
(PDF) Weaving a Social Data Web with Semantic Pingback.
OntoWiki backlinks are rendered in the "Instances Linking Here" side ... Pingback client establishes a connection to the Pingback server on ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found