Consider a social media site where a user
(vertex) can share
(edge) the post
(vertex) of another user
.
When you construct the users feed, it would look something like this:
const myUserId = 123;
g.V(myUserId)
.as("myUser")
.union(
// posts of users the requesting user follows
__.out("follow").out("post"),
// posts shared by users the requesting user follows
__.out("follow").out("share"),
// posts of the requesting user
__.out("post")
)
So far so good, but I need to sort these posts with the following logic:
If the post has an incoming share
edge from a user I follow
, sort by the createdDate
property of that share
edge (sort by when the post was shared, not the date the post was created).
Otherwise, sort by the createdDate
property of the post
.
Something like:
.order()
.by(
__.inE("share")
.as("shareEdge")
.outV()
.in_("follow")
.hasId(myUserId)
.select("shareEdge")
.properties("createdDate"),
order.decr
)
.by("createdDate", order.decr)
The problem is that not all posts have a share
edge, so this throws an error.
Error: GraphQL error: Error: Error: Server error: {"requestId":"53e7e66c-302e-4521-ac39-b672b4cb52e6","code":"InvalidParameterException","detailedMessage":"The provided traverser does not map to a value: v[c9b66e21-f8fc-48e5-bdcd-c580248b3f52]->[VertexStep(IN,[share],edge)@[shareEdge], EdgeVertexStep(OUT), VertexStep(IN,[follow],vertex), NeptuneHasStep([~id.eq(f70a5a2d-f606-44b8-8fa6-1e359033223e)]), SelectOneStep(last,shareEdge), NoOpBarrierStep(2500), PropertiesStep([createdDate],property)]"} (499)
How can I sort by an edge property only if the edge exists, and fall back to a vertex property sort where it doesn't?
I think that you can solve this with coalesce()
. Here's a small sample graph (when asking questions about Gremlin it is always best to include some sample data as a Gremlin script):
g.addV('post').property('createdDate',1).as('p1').
addV('post').property('createdDate',2).as('p2').
addV('user').as('u1').
addE('share').to('p2').property('createdDate',0)
First the basic ordering using the vertex createdDate
:
gremlin> g.V().hasLabel('post').
......1> order().
......2> by('createdDate').
......3> valueMap(true)
==>[id:0,label:post,createdDate:[1]]
==>[id:2,label:post,createdDate:[2]]
Then, using coalesce()
in the order()
to include the logic you described:
gremlin> g.V().hasLabel('post').
......1> order().
......2> by(coalesce(inE('share').values('createdDate'),
......3> values('createdDate'))).
......4> valueMap(true)
==>[id:2,label:post,createdDate:[2]]
==>[id:0,label:post,createdDate:[1]]