Struggling with this query

Using the first data set from the tour…

I want to write a query that output all the nodes that have both Amit and Sarah as friends.

The expected result would be the Michael node.

I tried

{
 test(func: has(friend) ) @cascade {
    name@.
    uid
    friend @filter(eq(name@., "Sarah") AND eq(name@., "Amit")) {
      name@. 
    }
 }
}

outputs

  "data": {
    "test": []
  },

I don’t understand I can do a OR but not an AND:

{
 test(func: has(friend) ) @cascade {
    name@.
    uid
    friend @filter(eq(name@., "Sarah") OR eq(name@., "Amit")) {
      name@. 
    }
 }
}

Outputs

{
  "data": {
    "test": [
      {
        "name@.": "Sang Hyun",
        "uid": "0x3",
        "friend": [
          {
            "name@.": "Amit"
          }
        ]
      },
      {
        "name@.": "Michael",
        "uid": "0x7",
        "friend": [
          {
            "name@.": "Amit"
          },
          {
            "name@.": "Sarah"
          }
        ]
      }
    ]
  },

Hi @acz, I am a newbie here. Here’s my two cents:

The solution in your third post is not working as you expect. friend @filter(eq(name@., ["Catalina", "Amit"])) is basically the same as friend @filter(eq(name@.,"Catalina") OR eq(name@., "Amit")).

You can find it out by running the following query:

{
 hasMichaelORSang(func: has(friend) ) @cascade {
    name@.
    friend @filter(eq(name@.,["Michael", "Sang Hyun"])) {
      name@. 
    }
 }
}

To achieve what you want, I think the following can do it:

{
 hasMichael as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Michael"))
 }
 hasSang as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Sang Hyun"))
 }
 hasBothMichaelSang (func: uid(hasMichael)) @filter(uid(hasSang)) {
   name@.
 }
}

Since I am a newbie, I am not sure if this is the simplest and most efficient way to handle it. People can correct me if I am wrong and show a better way if there is one. Thanks.

1 Like
{
 test(func: has(friend) ) {
    friend @filter(eq(name@., "Sarah") OR eq(name@., "Amit") {
      c as count(uid)
    }
 }

 result(fun: uid(c)) @filter(eq(val(c), 2)) {
   uid
 }
}

Something on these lines should work. Basically, count the number of results and then pick the ones who have 2.

@janardhan: Can you confirm this?

The query suggested by @acz should work.

{
  hasAmit as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Amit")) {
      uid
    }
  }
  hasSarah as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Sarah")) {
      uid
    }
  }
  hasBothAmitAndSarah (func: uid(hasAmit)) @filter(uid(hasSarah)) {
    uid
    name@.
  }
}

If you were to use the count approach, search for count >=2 instead of eq(val©,2)

Is there any reason why the @filter(eq(name@., "Sarah") AND eq(name@., "Amit")) doesn’t work?

@filter(eq(name@., "Sarah" gives the list of people whose name is sarah, so the filter @filter(eq(name@., "Sarah") AND eq(name@., "Amit")) woud return a set of people whose name is both amit and sarah.(which would be empty set).

@filter(eq(name@., "Sarah") AND eq(name@., "Amit")) is the intersection of two lists.

1st list - Nodes which have name Sarah in any language
2nd list - Nodes which have name Amit in any language

Since no node has both the names, the intersection is empty.

^^^

Ok I get it… Is there a practical and efficient way to query for nodes that have both Sarah and Amit as friend?

Did you try this? Looks to me like it should work.

{
  hasAmit as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Amit")) {
      uid
    }
  }
  hasSarah as var(func: has(friend) ) @cascade {
    friend @filter(eq(name@.,"Sarah")) {
      uid
    }
  }
  hasBothAmitAndSarah (func: uid(hasAmit)) @filter(uid(hasSarah)) {
    uid
    name@.
  }
}

Thanks, yes it looks like it should work. I am just wondering how efficient this is.

I’ll will be pretty efficient. Internally, it will be created two lists of nodes, then intersecting them (then finding the name of each node in the intersection). All of these operations are efficient and fast.

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