0

I have a schema

<friend>: uid .
<owns_pet>: uid .
<person.age>: int @index(int) .
<person.name>: string @index(fulltext, term, trigram) .
<pet.name>: string @index(fulltext, term) .

with data

{
  set {
    _:a1 <person.name> "A1" .
    _:a1 <person.age> "43" .
    _:a2 <person.name> "A2" .
    _:a2 <person.age> "33" .
    _:a3 <person.name> "A3" .
    _:a3 <person.age> "37" .
    _:a1 <friend> _:a2 .
    _:a1 <friend> _:a3 .
    _:a3 <friend> _:a2 .
    _:p2 <pet.name> "P2" .
    _:p3 <pet.name> "P3" .
    _:a2 <owns_pet> _:p2 .
    _:a3 <owns_pet> _:p3 .
  }
}

Is it possible to create a query which returns only persons who has a friend, and this friend has a pet with name "P3"? I expect to see in result

"result": [
  {
    "name": "A1",
    "age": 43
  }
]

For now i was able to query:

{
  result (func: has(person.name)) @filter(has(friend)) {
    name: person.name
    age: person.age
    friend @filter(has(owns_pet)) {
      owns_pet @filter(eq(pet.name, "P3")) {
      }
    }
  }
}

but this also returns person "A3"

maksim
  • 458
  • 2
  • 6
  • 16

2 Answers2

2

Here's another query you could consider using @normalize to only return aliased predicates and @cascade to only return results that contain all the edges in the query:

{
  personWithFriendPetP3(func: has(person.name)) @normalize @cascade {
    name: person.name
    age: person.age
    friend {
      owns_pet @filter(eq(pet.name, "P3")) {
        pet.name
      }
    }
  }
}

Response:

{
  "data": {
    "personWithFriendPetP3": [
      {
        "name": "A1",
        "age": 43
      }
    ]
  }
}

Your answer would work great given that you'd set the reverse edges in the schema types for owns_pet and friend. It would do less work than the above query, given that it's using an indexed query in the root func with an equality check for the specific pet name first, and then traversing for the other friends.

The query in this answer would first find all the people who have names in the root func, and then check whether their friend's pet name is P3.


Dgraph docs:

https://docs.dgraph.io/query-language/#normalize-directive

https://docs.dgraph.io/query-language/#cascade-directive

Daniel Mai
  • 341
  • 1
  • 7
1

Found one solution, that returns needed results:

{
  var (func: eq(pet.name, "P3")) {
    ~owns_pet {
      ~friend {
        u as uid
      }
    }  
  }

  result (func: uid(u)) {
    name: person.name
    age: person.age
  }
}

but i don't know if it's a correct way.

maksim
  • 458
  • 2
  • 6
  • 16