Get distinct nodes

Hello,

I need to get distinct nodes by a given criteria. For example, I have tree customer nodes linked to one node(In the next example: 3 nodes share “Somehting In Common” node). Any of the customer nodes is linked to name node. But some customer nodes can share same name.

Given the following graph
{
set {
_:l “Something In Common” .

_:a “1123” .
_:b “1124” .
_:c “1125”.

_:a <linked_to> _:l .
_:b <linked_to> _:l .
_:c <linked_to> _:l .

_:aName “A A” .
_:cName “C C” .
_:anotherName "Another Not Taken into Account " .

_:a <has_name> _:aName (timestamp= “2018-05-21”) .
_:b <has_name> _:aName (timestamp=“2018-05-22”) .
_:c <has_name> _:cName (timestamp=“2018-05-23”) .
}
}

How can I count, what is the number of distinct names related to “Something In Common” node?

I have tried with something like
{
me(func: eq(commondInfo, “Something In Common”) ) {
commondInfo
~linked_to @groupby(name) {
has_name_count as count(name)
}
sum(val(has_name_count))
}
}
but it does not work. Is there a way to make a distinct operation? I have checked in the documentation and forum, but I cannot find an example.

Thank you,
Stanka

You could try to create a tree of nodes and use @Reverse (for better use case). Like:

schema:
linked_to: uid @reverse @count .
Common_name: string @index(exact) .

In that case you change this

{
set {
_:l <Common_name> "Something In Common" .
_:lK <more_details> "More details about Something In Common" .
_:T <Common_name> "Something In Common2" .
_:TK <more_details> "More details about Something In Common" .

_:a <name> "1123" .
_:b <name> "1124" .
_:c <name> "1125".

_:l <linked_to> _:a (timestamp="2018-05-23") .
_:l <linked_to> _:b (timestamp="2018-05-23") .
_:T <linked_to> _:c (timestamp="2018-05-23") .

_:aName <name> "A A" . #I don't know if its needed
_:cName <name> "C C" . #I don't know if its needed
_:anotherName <name> "Another Not Taken into Account " . #I don't know if its needed

_:a <has_name> _:aName (timestamp="2018-05-21") .
_:b <has_name> _:aName (timestamp="2018-05-22") .	
_:c <has_name> _:cName (timestamp="2018-05-23") .
}
}

Queries you can use:

{
#Find all and expand all
 usersIncommon(func: has(Common_name)){
  expand(_all_){expand(_all_)}
}
}
{
#Filter by Common_name and expand all
  usersIncommon(func: has(Common_name)) @filter(eq(Common_name, "Something In Common")){
  uid
  Common_name
  linked_to {
  name
  }
}
}
{
#Using two blocks to filter and return a clean result
 var(func: has(Common_name)) @filter(eq(Common_name, "Something In Common")){
  uid
  Common_name
  myvar AS linked_to{
  name
  }
}
  usersIncommon(func: uid(myvar)) {
    uid
    has_name
    name  
}
}
{
#count linked by linked_to
  usersIncommon(func: has(Common_name)) {
  uid
  Common_name
  linked_to {
  name
  }
    count(linked_to)
}
}

Thank you very much for your answer. Expand is a pretty cool function! But I need a little more help to get the count I need. I will change a little bit the mutation script.

schema:
linked_to: uid @reverse @count .
ip: string @index(exact) .
{
set {
#common ip
_:l <ip> "123.123.123.123" .
_:l <ip_counry_range> "Some ip country range". 
_:T <ip> "123.123.123.124" .
_:T <ip_country_range> "Some other ip country range.NOTE: We don't care of this ip in the search result, we just have in the database" .

 #customers
_:a <customerId> "1123" .
_:b <customerId> "1124" .
_:c <customerId> "1125".

#customer has used the common ip on the following dates  
_:l <linked_to> _:a (timestamp="2018-05-23") .
_:l <linked_to> _:b (timestamp="2018-05-23") .
_:T <linked_to> _:c (timestamp="2018-05-23") .

#customer name nodes, more than one customer can share one name
_:aName <name> "A A" . 
_:cName <name> "C C" . 
_:anotherName <name> "Another Not Taken into Account " . #I don't know if its needed

#custoemrs used that names on a given date
_:a <has_name> _:aName (timestamp="2018-05-21") .
_:b <has_name> _:aName (timestamp="2018-05-22") .	
_:c <has_name> _:cName (timestamp="2018-05-23") .
}
}

I need to get the count of the names, starting from something in common node. For example you have an customer base, full of customers that can have common names and ips that customers have used in the past. So ip can be something in common. And I want to take what is the count of the unique names for a given ip.
In the given graph above, for ip 123.123.123.123 we have two customers with same name(a and b). If I count the linked_to edge the names count will be two, which is not true since it is actually one.

{
#count linked by linked_to
  usersIncommon(func: has(ip))  @filter(eq(ip, "123.123.123.123")){
  uid
  ip
  linked_to {
  name
  }
    count(linked_to)
}
}

So how can I count the name nodes not linked_to edges?
Similar to sql llike syntax: select distinct data from some table;

Count only works on links via UID, so you should always think of “nodes levels”.

In case you would have to change has_name to UID and if you need “@Reverse” (if it is not already).

In this case your query would be - Try this out:

{
  usersIncommon(func: has(ip))  @filter(eq(ip, "123.123.123.123")){
    uid
    ip
  linked_to {
      name
      has_name { #if your nodes are reverse use like this "~has_name"
       name
            }
       count(has_name)
  }
    count(linked_to)
   
}
}

Maybe I did not quite understand what you want. I would recommend giving a hand in the documentation on the language. https://docs.dgraph.io/query-language/ There are many possibilities, so I understand you might have to create more than one block with variables to filter out each need and generate the count. In that case you need to mix your business-logic(app logic) knowledge with the Dgraph language.

I believe that by mastering language you can do a lot. However, not everything should be done by DB alone. Dgraph has many functions, but you can not do everything.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.