Getting all properties for a node with multiple constraints two nodes out


(Michael) #1

My app allows users to search for classifieds listings (motorcycles). One of the possible queries they can currently perform is “show me touring bikes offered by dealers”. Both “dealer” and “touring” are two-plies out from the listings:
Listing -> Feed -> Dealer (optional)
Listing > VehicleModel -> VehicleStyle

I attach the query that I have so far - the first one just lists the data so you can see what is in there, the second query tries to match it. I have trouble figuring out though how I can add the second constraint (VehicleModel -> VehicleStyle) to the second query, and still get all the optional properties of the listing (such as price_usd which is actually empty). I attach my current queries/results, and a graphical representation of the problem.
Thanks for any help!

query pastebin: https://pastebin.com/vQLLTQ4m
result pastebin: https://pastebin.com/3jf6SWyq

QUERIES

 {
     node(func: uid(0x2802)) {
       feed {
         uid
         name
         dealer {
           uid
           name
       }
    }

    vehicle.model {
      uid
      name
      vehicle.style { 
      	uid
        name
      }
    }
    
    type
    uid
    name
    price_usd
  }

  
  #want: listings that are touring hondas by dealers
  #this only gets listings that are 
  #hondas by dealers, but doesn't have
  #a vehicle.style constraint


  dealerfeed(func: has(dealer)) @filter(eq(type, "Feed")) {
    ~feed @filter(eq(type, "Listing")){
      uid
    	name
      price_usd
  	}    
  }
}

RESULTS

{
  "data": {
    "node": [
      {
        "feed": [
          {
            "uid": "0x2b50",
            "name": "Best Powersports New Bikes",
            "dealer": [
              {
                "uid": "0x2b51",
                "name": "Best Powersports"
              }
            ]
          }
        ],
        "vehicle.model": [
          {
            "uid": "0x2b53",
            "name": "Honda ST",
            "vehicle.style": [
              {
                "uid": "0x2b4d",
                "name": "Touring"
              }
            ]
          }
        ],
        "type": "Listing",
        "uid": "0x2802",
        "name": "Honda ST 1100 Motorcycle"
      }
    ],
    "dealerfeed": [
      {
        "~feed": [
          {
            "uid": "0x2802",
            "name": "Honda ST 1100 Motorcycle"
          }
        ],
        "uid": "0x2b50"
      }
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 84900,
      "processing_ns": 11426300,
      "encoding_ns": 2410100
    },
    "txn": {
      "start_ts": 119547
    }
  }
}

(Manish R Jain) #2

@MichelDiz can you help?


(Michel Conrado) #3

I’m not 100% sure if I get the whole issue. But I’ve created a block to apply the constraints, for this I had to make ~vehicle.style and ~vehicle.model as reverse edges. So I can apply in the same query the second rule.

You could greatly reduce the size of this query using uid_in. But you would need to know upfront the UID to be used in the query. Because uid_in does not support variables. Only GraphQL variables.

Query

{
  var(func:eq(name,"Touring")) {
      uid
      name
     ~vehicle.style{
            uid
            name
       ~vehicle.model{
            uid
            name
		    GetDealer as feed	@filter(eq(name,"Best Powersports New Bikes"))
  				}
      }
  }
# The normal direction structure of this block above does not work, 
# to apply the two rules must necessarily be in reverse.
# So GetDealer will only be true if the "Touring" is true together the GetDealer itself.
# if there's no "Touring" the result will be empty, if Touring is true but 
# GetDealer don't. Will be empty
  
  dealerfeed(func: uid(GetDealer)) {
      uid
      name
      dealer {
        name
      }
    ~feed @filter(eq(type, "Listing")){
      uid
      name
      price_usd
      vehicle.model {
      uid
      name
      vehicle.style { 
      	uid
        name
      }
    }
  	}    
   }
}

Result

{
  "data": {
    "dealerfeed": [
      {
        "uid": "0xfb777",
        "name": "Best Powersports New Bikes",
        "dealer": [
          {
            "name": "Best Powersports"
          }
        ],
        "~feed": [
          {
            "uid": "0xfb776",
            "name": "Honda ST 1100 Motorcycle",
            "vehicle.model": [
              {
                "uid": "0xfb779",
                "name": "Honda ST",
                "vehicle.style": [
                  {
                    "uid": "0xfb77a",
                    "name": "Touring"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

(Michel Conrado) #4

I have another option. More simple but you need to do checks in your client side.

{
  dealerfeed(func:eq(name,"Best Powersports New Bikes")) @recurse(depth: 5) {
      uid
      name
      dealer
      ~feed
       Applied as vehicle.style @filter(eq(name,"Touring"))
   		 vehicle.model
      }
  check(func: uid(Applied)) {
    uid
    name
  }
}

To check if both rules were applied you would need to check if the last block returned something.

Result

{
  "data": {
    "dealerfeed": [
      {
        "uid": "0xfb777",
        "name": "Best Powersports New Bikes",
        "dealer": [
          {
            "uid": "0xfb778",
            "name": "Best Powersports"
          }
        ],
        "~feed": [
          {
            "uid": "0xfb776",
            "name": "Honda ST 1100 Motorcycle",
            "vehicle.model": [
              {
                "uid": "0xfb779",
                "name": "Honda ST",
                "vehicle.style": [
                  {
                    "uid": "0xfb77a",
                    "name": "Touring"
                  }
                ]
              }
            ]
          }
        ]
      }
    ],
    "check": [
      {
        "uid": "0xfb77a",
        "name": "Touring"
      }
    ]
  }
}

(Michael) #5

Thanks for the suggestions. The result I am interested in is looking for any bike offered by a dealer - not the specific dealer. The Touring constraint is fine. Also, I guess I should add eq(type, “Listings”) etc… type constraints as well at all levels of the query too?

Here is my query in pseudo-query language:
get(listings) where feed->dealer != nil && vehicle.model->vehicle.style == 0xfb77a

Also, I will know the uids of the vehicle.style I am intersted in in the client - there is only 10 or so of them - how can I use uid_in in this scenario?


(Michel Conrado) #6

So your query does this.

{
dealerfeed(func: has(dealer)) @filter(eq(type, "Feed")) {
    ~feed @filter(eq(type, "Listing")){
      uid
    	name
      price_usd
      vehicle.model {
           uid
           name
           vehicle.style { 
        	uid
            name
          }
       }
  	}    
  }
}

Don’t use type in all nodes. only when it is necessary to look for them individually in some scenario. You can use “has(vehicle.style)” for example for some reason.

Okay, let’s say you change your model to the structure below.

{
  "set": [
      {
        "feed": [
          {
            "name": "Best Powersports New Bikes",
            "dealer": [
              {
                "name": "Best Powersports"
              }
            ]
          }
        ],
        "vehicle.model": [
          {
            "name": "Honda ST"
          }
        ],
        "vehicle.style": [
          {
            "name": "Touring"
          }
        ],
        "price_usd": "2990",
        "type": "Listing",
        "name": "Honda ST 1100 Motorcycle"
      }
    ]
}

Query

# 0xfb788 = Honda ST model
# The query gets much more simpler.
{
  dealerfeed(func: has(dealer)) {
    ~feed @filter(eq(type, "Listing") AND uid_in(vehicle.model, 0xfb788 ) ){
      uid
      name
      price_usd
      vehicle.model{ name }
      vehicle.style{ name }
  	}    
  }
}

Result

{
  "data": {
    "dealerfeed": [
      {
        "~feed": [
          {
            "uid": "0xfb785",
            "name": "Honda ST 1100 Motorcycle",
            "price_usd": "2990",
            "vehicle.model": [
              {
                "name": "Honda ST",
                "uid": "0xfb788"
              }
            ],
            "vehicle.style": [
              {
                "name": "Touring",
                "uid": "0xfb789"
              }
            ]
          }
        ]
      }
    ]
  }
}

You can try also normalize.

{
  dealerfeed(func: has(dealer)) @normalize {
    ~feed @filter(eq(type, "Listing") AND uid_in(vehicle.model, 0xfb788 )){
      uid
      name : name
      price_usd : price_usd
      vehicle.model { vehicle.model : name }
      vehicle.style { vehicle.style : name }
  	}    
  }
}

Result

{
  "data": {
    "dealerfeed": [
      {
        "name": "Honda ST 1100 Motorcycle",
        "price_usd": "2990",
        "vehicle.model": "Honda ST",
        "vehicle.style": "Touring"
      }
    ]
  }
}