`eq` function not behaving as expected

I’m learning dgraph. I have a schema with

  • Predicate: ContactEmailAddress.email
  • Type: string
  • Indices: term

If I execute the following query in Ratel:

query {
  test(func: type(ContactEmailAddress)) {
    uid
    email
  }
}

I see a graph containing a node with uid: "0x2726" and email: "test@example.com".

If I execute the following query in Ratel:

query {
  test(func: eq(ContactEmailAddress.email, "test@example.com")) {
    uid
    email
  }
}

Then I see nothing. The query executes without error, but nothing is returned. Why? By my reading of the docs, this seems like a very straightforward usage of the eq function. I expect the second query to return the same result as the first query (in this case).

Edit:
I’m using the dgraph/standalone docker image as listed in the DQL getting started guide.

Did you set:

@index(exact)

?

J

Thanks for weighing in, but the docs state that a term index should allow the use of the eq function. Additionally, I’m not getting any kind of “this query requires an index” error.

I just meant you need an index, as it helps to share your schema here.

Try just the email:

query {
  test(func: eq(email, "test@example.com")) {
    uid
    email
  }
}

or I would think this would work:

query {
  test(func: type(ContactEmailAddress)) @filter(eq(email, "test@example.com")) {
    uid
    email
  }
}

Not sure whether or not eq can have child predicates.

J

Try:

query {
  test(func: eq(email, "test@example.com")) {
    uid
    email
  }
}

It appears your predicate is just email not the dotted type notation.

I just meant you need an index, as it helps to share your schema here.

In case you missed it, my question begins by sharing my schema as it pertains to the question. But let me know if you think there are additional schema details that may be missing.

The query

query {
  test(func: eq(email, "test@example.com")) {
    uid
    email
  }
}

Results in:

{
  "name": "t",
  "url": "http://localhost:8080/query?timeout=20s&debug=true",
  "errors": [
    {
      "message": ": Predicate email is not indexed",
      "extensions": {
        "code": "ErrorInvalidRequest"
      }
    }
  ]
}

Which makes sense, because again my schema as detailed by Ratel is:

  • Predicate: ContactEmailAddress.email
  • Type: string
  • Indices: term

Furthermore, executing this query:

query {
  test(func: eq(ContactEmailAddress.email, "test@example.com")) {
    uid
    email
  }
}

Does not result in a Predicate ContactEmailAddress.email is not indexed error, implying that it is indexed.

@amaster507 It appears your predicate is just email not the dotted type notation.

I built the schema using graphql and uploading it via the /admin/schema endpoint, but then I added data using DQL (via the dgraph-js-http library). When I added data I used something like

{
  set: {
    'dgraph.type': 'ContactEmailAddress',
    uid: '_:emailId',
    email: "test@example.com",
  }
}

Do I need to instead do something like?

{
  set: {
    'dgraph.type': 'ContactEmailAddress',
    uid: '_:emailId',
    "ContactEmailAddress.email": "test@example.com",
  }
}

Thanks for the help!

1 Like

So assuming you have this:

type ContactEmailAddress {
  uid
  email @index(term)
}

you would add your info like this:

{
  set {
    _:contact <dgraph.type> "ContactEmailAddress" .
    _:contact <email> "test@example.com" .
  }
}

_:contact can be any name, just a placeholder to link the internal uid to the predicates.

or JSON version:

{
  set {
    "dgraph.type": "ContactEmailAddress",
    "email": "test@example.com"
  }
}

J

Yes.

2 Likes

Wow. Thank you so much. I never would have guessed this was the problem. This strikes me as such a non-intuitive API…just wow. But I’ve tested it and it works! Seriously, thanks so much.

Edit
For future readers, I found that the GraphQL on Existing Dgraph section of the dgraph docs touches on using DQL with GraphQL (though it’s still not as clear as amaster507's comment). Unfortunately, because of the name and since I’m just starting out (and don’t have an existing dgraph) I never read this section and it didn’t pop out to me when I was searching through the docs for answers.

2 Likes

So let me try to fill in some missing context. First if you have not yet, check out this reference:

So beyond that, GraphQL both the schema, queries, and mutations get rewritten into DQL and then processed.

Since GraphQL schema does not really handle the case of a predicate used by multiple types (outside of interfaces) it is possible that two predicates of two different types could be totally different. You could for instance have:

type Foo {
  name: String @search(by: [term])
  list: [Bar]
}
type Bar {
  name: String @search(by: [exact])
  list: [String]
}

So if Foo: name and Bar: name both mapped to just the predicate then it would have to be able to be indexed differently for each type. And as is illustrated with the Foo: list and Bar: list. The predicate types might not even be compatible across types. So to allow this unique predicate for each type and help distribute predicates in the cluster any GraphQL type field definitions that are not specifically mapped to a predicate using the @dgraph directive are automatically mapped to a dotted notation field indication what type the field belongs to. (A little gotcha when dealing with interfaces is the interface fields get mapped to the interface dotted predicate, not the type dotted predicate.

I understand being hesitant to dig into the RDF and DQL aspects, but when you cross that barrier you will wonder why it seemed so hard before to understand and why other graph databases aren’t doing things the same way.

On a side note about the terminology in Dgraph, they seem to take a more literal and fundamental meaning of the words. This probably arose from dealing with ESL developers and developing across language barriers. What exactly is an object and a property anways compared to what is a node and a predicate.

2 Likes

This is great information, thanks! And that post you linked to is an incredibly helpful resource!!