Recurse by way of intermediate list predicate

I Want to Do

I’m looking for a way to get recurse through a graph by way of intermediate list predicates. (I may have asked this before but I don’t see it, not sure. If I did I’ll delete.).

Abstract high level description: My graph is something like UserA liked Post1 posted by UserB liked Post2 posted by UserC. I’d like the query to return the pairs A/B and B/C (without the intermediate Posts).

This would be in contrast to a more typical UserA following UserB following UserC, where you can very easily use @recurse to get the relations. Basically, I want to collapse “liked Post posted by” to something like a typical “following” relation.

One possible wrinkle: I’d also like to get a count of these indirect relations between users.

Sample schema and data that will hopefully demonstrate this well enough:

schema {
	type User {
		user_username
		user_liked
	}
	user_username: string .
	user_liked: [uid] @reverse .

	type Post {
		post_title
		post_author
	}
	post_title: string .
	post_author: uid @reverse . # User
}

set {
	_:user-a <user_username> "User A" .
	_:user-a <dgraph.type> "User" .

	_:user-b <user_username> "User B" .
	_:user-b <dgraph.type> "User" .

	_:user-c <user_username> "User C" .
	_:user-c <dgraph.type> "User" .

	_:post-by-b <post_title> "Whatever by user B" .
	_:post-by-b <post_author> _:user-b
	_:post-by-b <dgraph.type> "Post" .

	_:user-a <user_liked> _:post-by-b .

	_:post-by-c <post_title> "Whatever by user C" .
	_:post-by-c <post_author> _:user-c
	_:post-by-c <dgraph.type> "Post" .

	_:post-by-c-2 <post_title> "Whatever by user C (2)" .
	_:post-by-c-2 <post_author> _:user-c
	_:post-by-c-2 <dgraph.type> "Post" .

	_:user-b <user_liked> _:post-by-c .
	_:user-b <user_liked> _:post-by-c-2 .
}

and I’d like to query something like:

query query($startingUid: string) {
  tmp(func: uid($startingUid)) @filter(type(User)) @recurse(depth: 5) {
    uid
    user_liked @filter(type(Post)) @groupby(post_author) {
      count(uid)
    }
  }
}

to get (User A, User B, 1) and (User B, User C, 2).

What I Did

I tried a query like:

query query($startingUid: string) {
  tmp(func: uid($startingUid)) @filter(has(user_liked)) @recurse(depth: 5) {
    uid
    user_liked @filter(type(Post))
    ~user_liked @filter(type(User))
  }
}

and it returns something possibly useful, but I can’t figure out how to get the counts I want from it, at least from Dgraph. I guess I could calculate them in the application?

I’ve considered using a separate list predicate that stores the relationship I care about explicitly (user_liked_post_by: [uid] .) in addition to the user_liked predicate (which I also care about), but obviously I’d need to remember to remove the user_liked_post_by entry when all relevant user_liked entries are removed, and that ain’t great.

Dgraph Metadata

dgraph version

root@268265c2efd2:/dgraph# dgraph version
[Decoder]: Using assembly version of decoder
Page Size: 4096

Dgraph version : v20.11.0-11-gb36b4862
Dgraph codename : tchalla
Dgraph SHA-256 : f7f7ff6dbf0c8d99ee56dd0c61c22106baffdb194fe98167a5ab458af8f2096b
Commit SHA-1 : b36b4862
Commit timestamp : 2020-12-17 23:41:53 +0530
Branch : release/v20.11-slash
Go version : go1.15.5
jemalloc enabled : true

For Dgraph official documentation, visit https://dgraph.io/docs/.
For discussions about Dgraph , visit http://discuss.hypermode.com.

Licensed variously under the Apache Public License 2.0 and Dgraph Community License.
Copyright 2015-2020 Dgraph Labs, Inc.