Filter to find nodes with unset @lang predicate

My schema contains
name: string @lang @index(fulltext) .

I would like to find all nodes that don’t have a ‘name’ predicate set in a given language. How do I do this?

Not sure if I got your question. Can you reformulate?
Even tho, from what I got I think this query covers:

{
  q(func: has(<name@.>)) @filter(NOT has(<name@hi>)) {
    name@en
  }
}

This query is a bit expensive tho.

PS. This is actually a bug. Has isn’t working with lang at all.

OK, for example: I want to build a query that yields nodes with no “name@de” predicate, regardless whether they have a ‘name’ set in any other language.

This query gives me a node that has no “name@de” predicate:

  unnamed_node(func: uid(0x5e3c)) {
    uid
    name@de
  }

… but this doesn’t give me anything:

  q(func: has(name@.)) @filter(NOT has(name@de)) {
    uid
  }

although I expected 0x5e3c to be part of the result.

If the 0x5e3c has name@de, it will be filtered out. As we are using NOT has. That query means "Give me any node who has lang tag and then filter out those who have @de ". So that’s an expected result. Also, the node should have at least a lang in its records.

A solution would be using type(MyType)

{
  q(func: type(User)) @filter(NOT has(<name@de>)) {
    name@en
  }
}

It doesn’t have “name@de”, and it does have another lang tag. I can use a type function as well, it doesn’t make a difference for me:

{
  unnamed_node(func: uid(0x5e3c)) {
    uid
    name@.
    name@de
  }
  q(func: type(Marque)) @filter(NOT has(name@de)) {
    uid
  }
}

Result:

  "data": {
    "unnamed_node": [
      {
        "uid": "0x5e3c",
        "name@.": "Kulak"
      }
    ],
    "q": []
  }

Does it has the dgraph.type?

{
        "uid": "0x5e3c",
        "name@.": "Kulak",
        "dgraph.type.": "Marque"
}

Yes.

      {
        "uid": "0x5e3c",
        "name@.": "Kulak",
        "dgraph.type": [
          "Marque"
        ]
      }

can you use angular brackets?

{
  unnamed_node(func: uid(0x5e3c)) {
    uid
    name@.
    name@de
  }
  q(func: type(Marque)) @filter(NOT has(<name@de>)) {
    uid
  }
}

This is odd, but feels like the angular brackets are mandatory in this case as it is not a regular predicate.

PS2. It is actually a bug. Has isn’t working with lang at all.

With the query you posted (with angular brackets), I get a lot of results, but some of them have “name@de”, so it’s not the filtered result I expected.

Thanks for the feedback!

Actually, see this

{
#  q0(func: uid(0x2)) {
#    uid
#    name@*
#  }
  q1(func: has(name@.)) @filter(NOT has(<name@en>)) {
    uid
    name@en
  }
  q2(func: type(Marque)) @filter(NOT has(<name@en>)) {
    uid
    name@en
  }
  q3(func: type(Marque)) @filter(NOT has(name@en)) {
    uid
    name@en
  }
  q4(func: has(name@.)) @filter(NOT has(name@en)) {
    uid
    name@en
  }

}

Response

{
  "data": {
    "q1": [
      {
        "uid": "0x2",
        "name@en": "Kulak"
      }
    ],
    "q2": [
      {
        "uid": "0x2",
        "name@en": "Kulak"
      }
    ],
    "q3": [],
    "q4": []
  }

The q1 and q2 shouldn’t have a response. All of them should be empty. So is the angular brackets which aren’t working. Can you check again your data?

Yup, same here. q1 and q2 return an unfiltered set of results. What are the angular brackets supposed to do anyway?

What do you mean?

They avoid issues with special characters.

Anyway, this situation is strange. I’ll keep digging and formulate issues about it if so.