What I want to do
Considering this schema: (GraphQL schema being used in DQL)
type Address {
id: ID!
tempCity: String @search(by: [exact])
city: City
state: State
}
type City {
id: ID!
name: String!
inState: State
hasAddresses: [Address] @hasInverse(field: "city")
}
type State {
id: ID!
name: String! @id
hasCities: [City] @hasInverse(field: "inState")
hasAddresses: [Address] @hasInverse(field: "state")
}
I have Address nodes that have both a tempCity
and a state
predicate/edge set. I need to update these addresses and create the city edge to the correct City node. The tricky part is that using the name attribute alone is not enough because the same city can be in multiple states. There are 25 states with the city ‘Madison’ so I need to also look at the City node to make sure it is the correct city in the correct state.
What I did
I created this query to start the process of creating the correct upsert statement.
{
Address(func: eq(Addr.tempCity,"Madison")) {
uid
Addr.tempCity
Addr.city { uid City.name }
state as Addr.state { uid State.name }
}
City(func: eq(City.name,"Madison")) @cascade {
uid
City.name
City.inState @filter(uid(state)) {
uid
State.name
}
}
}
Response Data
{
data:{
Address:[
{
uid:"0x2dd9cd"
Addr.tempCity:"Madison"
Addr.state:{
uid:"0x4a29a"
State.name:"Wisconsin"
}
}
{
uid:"0x31cd69"
Addr.tempCity:"Madison"
Addr.state:{
uid:"0x2a05f"
State.name:"Alabama"
}
}
{
uid:"0xfffd8d6aa9d517a3"
Addr.tempCity:"Madison"
Addr.state:{
uid:"0x4c3be"
State.name:"Florida"
}
}
{
uid:"0xfffd8d6aa9d52340"
Addr.tempCity:"Madison"
Addr.state:{
uid:"0x2a05f"
State.name:"Alabama"
}
}
]
City:[
{
uid:"0x16802"
City.name:"Madison"
City.inState:{
uid:"0x2a05f"
State.name:"Alabama"
}
}
{
uid:"0x408f5"
City.name:"Madison"
City.inState:{
uid:"0x4a29a"
State.name:"Wisconsin"
}
}
{
uid:"0x4b05e"
City.name:"Madison"
City.inState:{
uid:"0x4c3be"
State.name:"Florida"
}
}
]
},
...
The problem is that there are 25 different Cities that get returned without the @cascade
and with the cascade I get three cities that match the three unique ‘Madison’ cities that need to be mapped. I cannot figure out the next step without manually also creating a unique upsert statement for each City/State combination.
The following does not work because it will incorrectly link every one of the addresses to all three of the cities instead of the specific one that is related through the State nodes
upsert {
query {
address as var(func: eq(Addr.tempCity,"Madison")) {
uid
Addr.tempCity
Addr.city { uid City.name }
state as Addr.state { uid State.name }
}
city as var(func: eq(City.name,"Madison")) @cascade {
uid
City.name
City.inState @filter(uid(state)) {
uid
State.name
}
}
}
mutation {
uid(address) <Address.city> uid(city) .
}
}
The only ugly solution I can come up with is:
upsert {
query {
address as var(func: eq(Addr.tempCity,"Madison")) @cascade {
uid
Addr.tempCity
state as Addr.state @filter(eq(State.name,"Wisconsin")) { uid State.name }
}
city as var(func: eq(City.name,"Madison")) @cascade {
uid
City.name
City.inState @filter(uid(state)) {
uid
State.name
}
}
}
mutation @if(eq(len(city),1)) {
uid(address) <Address.city> uid(city) .
}
}
I really want a solution where I can do this update without needing to run a unique upsert statement for every possible tempCity/State combination.