Filter logic at different query depths

Stepping out on a limb here. Is there any way to possibly do logic between two different levels in a single query?

type Person {
  id: ID!
  name: String @search(by: [fulltext])
}

type Book {
  id: ID!
  title: String @search(by: [fulltext])
  author: [Person]
}

What if I wanted to find every book that had either the word James in the title or as the author?

{ 
  queryBook(filter: {title: {alloftext: "James"}}) { 
    id
    title
    author(filter: {name: {alloftext: "James"}}) {
      id
      name
    }
  }
}

This would only get the books that have an AND logic but how could this be done in a single query with OR logic? An answer using Dgraph (GraphQL±) is acceptable, but not preferable. I understand that GraphQL has its limitations to predefined schema where gragphql± is a bit more flexible in that area and it can use variables.

This is not actually an AND.

  1. I think by AND you meant: query only the books that have a title "James" AND their author's name is "James" as well. But, this is a bit different.
  2. The query here will mean this: query only the books that have a title "James" and then for those books, query their author only if the author name is "James". i.e., even if some book’s title is “James” and it’s author’s title is “Harold”, it will still fetch the book, but not the author.

And, for the AND I explained here in 1, it can be done with @cascade on top query, like this:

{ 
  queryBook(filter: {title: {alloftext: "James"}}) @cascade { 
    id
    title
    author(filter: {name: {alloftext: "James"}}) {
      id
      name
    }
  }
}

I don’t think it could be done in a single query with GraphQL, at present. We would have to think about supporting this kind of logic in GraphQL.

With GraphQL± this is possible in the following way:

query {
	JamesAsTitle as var(func: alloftext(Book.title, "James"))
	JamesAsAuthor as var(func: type(Book)) @cascade {
		Book.author @filter(alloftext(Person.name, "James"))
	}
	JamesBooks(func: type(Book)) @filter(uid(JamesAsTitle) OR uid(JamesAsAuthor)) {
		uid
		expand(_all_) {
			expand(_all_)
		}
	}
}

So here is where I am headed with this concept of user definable multi-level filter logic. Just interested in feedback.

  1. UI provides logic to build filters for predefined fields and save these filters in the database for the user.
  2. User can then make a request to use a set of filters with conjunction logic.
  3. I am writing a @custom script with a lambda function to accept variables with tells the script which filters to use.
  4. Then it makes a request back to dgraph to get those filter values.
  5. From these filter values it actually generate a DQL (or whatever we are calling it now) and
  6. Then sends that to dgrqph to
  7. Return a list of uids that fully appease the filters.
  8. These uids are returned to the UI and then
  9. Used to get the actual data to display and paginate.

This solves a few problems.

  • Paginating with cascade
  • Many queries required for deep nested logic conjucted together.

That is a nice approach!

Just FYI, experimental DQL support in GraphQL is available in master. Have a look here. So, maybe you could use that to make your flow more efficient. But, it is the very beginning of this feature, so things may change anytime.

yes! I have been watching the integration of DQL into custom as well as upcoming JS integration into Custom. Maybe that could make this whole process doable without an external script (lambda function)