Magic Script for Recreating Inverse Relationships for GraphQL with DQL?

Well, I am not sure how or when, but somewhere along the way I lost all of my inverse relationships for at least one three types. I have one side of the relationships still just need to recreate the opposite hasInverse side. There is a mixture of interfaces in here too which make the DQL a little complicated. Let me provide some data examples to work with:

GraphQL Schema Snippet:

type State {
  name: String! @id
  usedBy: [Address] @hasInverse(field: state)
}
interface Addr {
  id: ID!
  state: State
}
type Address implements Addr {
  usedBy: [HasAddress] @hasInverse(field: address)
}
type HasAddress {
  id: ID!
  for: Contact @hasInverse(field: hasAddresses)
  address: Address! @hasInverse(field: usedBy)
  isPrimary: Boolean @search
  isMailing: Boolean @search
}
type Contact {
  id: ID!
  hasAddresses: [HasAddress] @hasInverse(field: for)
}

Here are two DQL queries showing unmatched data:

{
  queryState(func: type(State)) @cascade {
    uid
    State.name
    State.usedBy {
      uid
      dgraph.type
    }
  }
  queryAddress(func: type(Address)) @cascade {
    uid
    Addr.state {
      uid
      State.name
      dgraph.type
    }
  }
}

Results Snippet:

{
  "data": {
    "queryState": [
      {
        "uid": "0x478a8",
        "State.name": "Oklahoma",
        "State.usedBy": [
          {
            "uid": "0x40355",
            "dgraph.type": [
              "Address"
            ]
          }
        ]
      },
      {
        "uid": "0x47b87",
        "State.name": "Arkansas",
        "State.usedBy": [
          {
            "uid": "0x2a558e",
            "dgraph.type": [
              "Addr",
              "Address"
            ]
          }
        ]
      }
    ],
    "queryAddress": [
      {
        "uid": "0x2f2e",
        "Addr.state": {
          "uid": "0x167d2",
          "State.name": "Alaska",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f34",
        "Addr.state": {
          "uid": "0x167d2",
          "State.name": "Alaska",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f4c",
        "Addr.state": {
          "uid": "0x2a05f",
          "State.name": "Alabama",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f5c",
        "Addr.state": {
          "uid": "0x2a05f",
          "State.name": "Alabama",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f62",
        "Addr.state": {
          "uid": "0x2a05f",
          "State.name": "Alabama",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f63",
        "Addr.state": {
          "uid": "0x2a05f",
          "State.name": "Alabama",
          "dgraph.type": [
            "State"
          ]
        }
      },
      {
        "uid": "0x2f66",
        "Addr.state": {
          "uid": "0x2a05f",
          "State.name": "Alabama",
          "dgraph.type": [
            "State"
          ]
        }
      },
      # ...
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 100942,
      "processing_ns": 53174272,
      "encoding_ns": 35421799,
      "assign_timestamp_ns": 1386688,
      "total_ns": 92303661
    },
    "txn": {
      "start_ts": 1677836
    },
    "metrics": {
      "num_uids": {
        "Addr.state": 14197,
        "State.name": 608,
        "State.usedBy": 307,
        "_total": 30222,
        "dgraph.type": 303,
        "uid": 14807
      }
    }
  }
}

I would expect that the Addr.state num_uids should be closely relative to State.usedBy, but they are not. I literally only get the first two results only for the queryState function.

What I need to do is write the perfect script that for every Addr.state produces the inverse State.usedBy

Then I need to go through at least a half dozen other relationships and fix them with the similar script.

What I don’t want to do is with Upsert make it where it maps all to one and one to all. This is a live data set so this fix needs to be correct the first time.

@MichelDiz, any chance you can help me with the correct snippet to fix these relationships?

Are you sure this isn’t a false alarm? Maybe the metrics are duplicated. I personally have no idea if the metrics are per UID or per “print”. Need to be checked.

Update: I have checked. And it is not duplicated.

The results is what triggered the investigation that found the metrics. I use the Addr.State for display and then I use the State.usedBy for search lookups. These should be kept in harmony with the hasInverse unless I messed it up somewhere else with DQL.

Currently I only have two addresses that are in the search lookup but in the results snippet you will see that I have a ton of Alabama addresses that should be in the lookup and all of the other states too that don’t appear.

Got it.

Summarizing what I understood. You had a GQL schema working normally. Then you made some edits via DQL and ended up breaking the relations used in hasInverse. Right?

Well, I don’t think that any DQL query would solve it. Once you lost the relation, you have to check address by address. Unless you had references in both node targets(like a history). That way a DQL Upsert would be able to fix it. But we know that nobody does that(maintain a history), neither the Dgraph’s GraphQL feature.

Would be interesting to have an atomic history of edges relations. So cases like this would be easy to revert.

What search? DQL or GQL?

It is DQL but it is basically just traversing the relationship backwards to get to the nodes of interest

I will just have to write a JS script to generate the missing data