Filter by relation predicate?


(James) #1

hi,
ive a relation role for user,
how do i get all users with specific role.name?
for example: role.name=‘admin’ or ‘staff’ ?

users(func: eq(_type, "user") {
    uid
    _type
    name
    first_name
    last_name
    roles {
      uid
      name
    }
})

What if i have more than 2 layers or more deep relationship that i wish to filter users ?


(Michel Conrado (Support Engineer)) #2

Try something like this:

JSON Mutation

{
  "set": [
    {
      "uid": "_:Admin",
      "_type": "Role",
      "name": "Admin"
    },
    {
     "_type": "user",
     "name": "Jack",
     "first_name": "Jack",
     "last_name": "Nicholson",
     "roles": { "uid": "_:Admin" }
    }
  ]
}

Query

{
  getDefaultUidForAdmin(func: eq(_type, "Role")) @filter(eq(name, "Admin")){
  uid
}

  users(func: eq(_type, "user")) @filter(uid_in(roles, "0x5" ))  
    {
    uid
    _type
    name
    first_name
    last_name
    roles {
      uid
      name
    }
}
}

About uid_in https://docs.dgraph.io/master/query-language/#uid-in

Cheers.


(James) #3

is these 2 separate query?


(Michel Conrado (Support Engineer)) #4

Yes, are two query blocks. The one above is just to know what UID put in uid_in(roles.

https://docs.dgraph.io/query-language/#multiple-query-blocks


(James) #5

means i need to obtain id first before query the second query


(Michel Conrado (Support Engineer)) #6

No, but you need to know what UID use tho.


(James) #7

is it possible to query without knowing uid but only knowing name?
can we do it using variable?

and is it possible to pass in multiple id to uid_in ?


(Michel Conrado (Support Engineer)) #8

For uid_in, no and no. But you can try other complex queries tho.

No wih uid_in, but you can use connectives AND, OR and NOT.


(Nikita Zaletov) #9

you can

roles as var(func: eq(name, "admin", "stuff"))

users(func: eq(_type, "user")) @cascade {
  roles @filter(uid(roles))
  uid
  name
}

but it will work slow

  1. use different names for edges for users and roles, to not index and lookup all name values but only related to role.
  2. don’t use eq for filtering by type, because it uses index lookup. create edge with typeUser name instead and query using has(typeUser) function
  3. don’t get all users and then filter by role. it’s not sql, you should use graph way instead:
result(func: eq(roleName, "stuff", "admin")) {
  ~roles {
    userName
    uid
  }
}

since you know that roles edge is always connecting user and role, you can use reverse edge to retrieve user by role. you can save users in a var and use in another block.

var(func: eq(roleName, "stuff", "admin")) {
  users as ~roles
}

users(func: uid(users)) {
  uid
  userName
}

if roles edge in your schema is used not only for users, you should modify your schema or use @filter(has(typeUser)) on ~roles edge (this option is worse)

result(func: eq(roleName, "stuff", "admin")) {
  ~roles @filter(has(typeUser)) {
    userName
    uid
  }
}

(James) #10

awesome tips man, thank you :slight_smile:


(James) #11

but looking at this query:

{
roles as var(func: eq(_type, "role") @filter(eq(name, "admin", "superadmin")))

users(func: eq(_type, "users")) @cascade {
...
}
}
  

how do i add in more filter for roles variable, like above , but it does not work


(James) #12

i tried this, no error, but didnt work

roles as var(func: eq(_type, "role")) @filter(eq(name, "admin", "superadmin"))

(Nikita Zaletov) #13

what did you mean when you say “didnt work”?


(Michel Conrado (Support Engineer)) #14

The correct syntax for multiple args values is

  • eq(predicate, [val1, val2, ..., valN])
    So: @filter(eq(name, ["admin", "superadmin"])))

Check https://docs.dgraph.io/query-language/#inequality


(James) #15

ah sorry, my mistake, i got this working:

roles as var(func: eq(_type, "roles")) @filter(eq(name, ["admin","superadmin"]))

users(func: eq(_type, "users")) @cascade {
  with_role @filter(uid(roles))
  uid
  email
}

but i could have done this instead:

users(func: eq(_type, "users")) @cascade {
  uid
  with_role @filter(eq(name, ["admin","superadmin"])) {
    uid
    name
  }
  email
}

(James) #16

is there anyway to support something like this?

{
  roles1 as var(func: eq(_type, "roles")) @filter(eq(name, "superadmin"))
  users(func: eq(_type, "users")) @filter(uid_in(with_role, roles1)) {
    uid
    email
    with_role {
      uid
      name
    }
  }
}

(Michel Conrado (Support Engineer)) #17

No for now. As Docs says

uid_in cannot be used at root, it accepts one UID constant as its argument (not a variable).

https://docs.dgraph.io/query-language/#uid-in


(James) #18

i did this:

{
  roles1 as var(func: eq(_type, "roles")) @filter(eq(name, "superadmin"))
  u1 as var(func: eq(_type, "users")) @cascade {
    uid
    with_role @filter(uid(roles1)){
      uid
      name
    }
  }
 
  roles2 as var(func: eq(_type, "roles")) @filter(eq(name, "admin"))
  u2 as var(func: eq(_type, "users")) @cascade {
    uid
    with_role @filter(uid(roles2)){
      uid
      name
    }
  }
    
  users(func: eq(_type, "users")) @filter(uid(u1, u2)) {
    uid
    email
    with_role {
      uid
      name
    }
  }
}