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.

1 Like

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

1 Like