Combine different predicates

hi there. i have a schema like this. nodes are linked one to another, each link belongs to customer, but when browsing, one customer can have access to other customer links:
_:A <link_customer1> _:B .
_:A <link_customer2> _:B .
_:A <link_customer1> _:C .
_:A <link_customer3> _: D .

for example, i need to count for A node all distinct outcoming nodes with link_customer1 link and link_customer2 predicates only. so, result should be 2 (B and C).

it works with storing all predicates in one and adding a “customers” facet, so query would be like:

nodes_count as count(link @facets(anyofterms(customers, “customer1 customer2”))

but as i understand this solution is quite bad for sharding due to using one predicate for all customers.

any ideas? in gremlin and cypher such query is not a problem

First of all, let me know if it’s all right below.

mutation

{
  set {
    _:Anna <name> "Anna" .
    _:Cris <name> "Cris" .
    _:Bob <name> "Bob" .
    _:Dude <name> "Dude" .
    
    _:Anna <link_customer1> _:Bob .
    _:Anna <link_customer2> _:Bob .
    _:Anna <link_customer1> _:Cris .
    _:Anna <link_customer3> _:Dude .
  }
}

Query

{
  me(func: eq(name, "Anna")) {
    name
   link_customer1 {
    expand(_all_)
  }
   link_customer2 {
    expand(_all_)
  }
   link_customer3 {
    expand(_all_)
  }
    count(link_customer1)
    count(link_customer2)
    count(link_customer3)

  }
}

Result


{
  "data": {
    "me": [
      {
        "name": "Anna",
        "link_customer1": [
          {
            "name": "Cris"
          },
          {
            "name": "Bob"
          }
        ],
        "link_customer2": [
          {
            "name": "Bob"
          }
        ],
        "link_customer3": [
          {
            "name": "Dude"
          }
        ],
        "count(link_customer1)": 2,
        "count(link_customer2)": 1,
        "count(link_customer3)": 1
      }
    ]
  },

thanks for the answer, but unfortunately it’s not what i actually want.
for your example, the sequence should be:

  1. get all nodes through link_customer1 and link_customer2 predicates
    (:Bob and :Cris) and (:Bob)
  2. get a union of these results with duplicates removed
    (:Bob and :Cris)
  3. count them or display their names
    so, result should be 2, or [{“name”: “Bob”}, {“name”: “Cris”}]

i see that there is no union on predicates in dgraph, but may be it’s possible to do somehow using vars…

ideal would be something like:
count(union(link_customer1, link_customer2)) and

union(link_customer1, link_customer2) {
  name
}

but it’s just a wish for future

seems like i found a solution:

{
	var(func: eq(name, "Anna")) {
		customer1_result as link_customer1 {
			uid
		}

		customer2_result as link_customer2 {
			uid
		}
	}
	
	count(func: uid(customer1_result, customer2_result)) {
		count(uid)
	}

	names(func: uid(customer1_result, customer2_result)) {
		name
	}
}
    "data": {
        "count": [
            {
                "count": 2
            }
        ],
        "names": [
            {
                "name": "Cris"
            },
            {
                "name": "Bob"
            }
        ]
    }

is there a more elegant way to achieve the same result?
thanks in advance

Maybe this

{
	var(func: eq(name, "Anna")) {
		customer1_result as link_customer1 {
			uid
		}

		customer2_result as link_customer2 {
			uid
		}
	}
	
	names(func: uid(customer1_result, customer2_result)) {
		name
    total : count(uid)
	}
}
{
  "data": {
    "names": [
      {
        "total": 2
      },
      {
        "name": "Cris"
      },
      {
        "name": "Bob"
      }
    ]
  }

yep, i tried this, but as for me it’s better to have these values in separate places.
i was wondering if there is a way to do this without using vars.

anyway, thanks for help!

I believe that this is the only way. Other mathematical parameters only work with variables. But count is perfect for what you want. If there are repeated UIDs it returns only unique values.

The form count(uid) counts the number of UIDs matched in the enclosing block.

@makitka @MichelDiz @mrjn

I filed a similar issue here: https://github.com/dgraph-io/dgraph/issues/2009

We moved toward using many separate predicates for sharding purposes but pay the price in cumbersome queries. For example if I want to retrieve all predicate values that are a “name” but there are 100 different “name” predicates, we have to list all 100 predicates in the query. What we need is a higher level grouping of predicates so that we get sharding efficiency without sacrificing query conciseness.

The way we get around this is by storing these groupings ourselves and using server side string building to build the queries…Because it’s not practical to write these queries by hand.