Fouad
Fouad

Reputation: 855

ArangoDb AQL Graph queries traversal example

I am having some trouble wrapping my head around how to traverse a certain graph to extract some data.

Given a collection of "users" and a collection of "places".

And a "likes" edge collection to denote that a user likes a certain place. The "likes" edge collection also has a "review" property to store a user's review about the place.

And a "follows" edge collection to denote that a user follows another user.

How can I traverse the graph to fetch all the places that I like with my review of the place and the reviews of the users I follow that also like the same place.enter image description here

for example, in the above graph. I am user 6327 and I reviewed both places(7968 and 16213) I also follow user 6344 which also happens to have reviewed the place 7968.

How can I get all the places that I like and the reviews of the people that I follow who also reviewed the same place that I like.

an expected output would be something like the following:

[
{
name:"my name",
place: "place 1",
id: 1
review,"my review about place 1"
},
{
name:"my name",
place: "place 2",
id: 2
review,"my review about place 2"
},
{
name:"name of the user I follow",
place: "place 2",
id: 2
review,"review about place 2 from the user I follow"
}
]

Upvotes: 2

Views: 3211

Answers (1)

David Thomas
David Thomas

Reputation: 2349

There are a number of ways to do this query, and it also depends on where you want to add parameters, but for the sake of simplicity I've built this quite verbose query below to help you understand one way of approaching the problem.

One way is to determine the _id of your user record, then find all the _id's of the friends you follow, and then to work out all related reviews in one query.

I take a different approach below, and that is to:

  • Determine the reviews you have written
  • Determine who you follow
  • Determine the reviews the people you follow have written
  • Merge together your reviews with those of the people you follow

It is possible to merge these queries together more optimally, but I thought it worth breaking them out like this (and showing the output of each stage as well as the final answer) to help you see what data is available.

A key thing to understand about AQL graph queries is how you have access to vertices, edges, and paths when you perform a query.

A path is an object in it's own right and it's worth investigating the contents of that object to better understand how to exploit it for path information.

This query assumes:

  • users document collection contains users
  • places document collection contains places
  • follows edge collection tracks users following other users
  • reviews edge collection tracks reviews people wrote

Note: When providing an id on each record I used the id of the review, because if you know that id you can fetch the edge document and get the id of both the user and the place as well as read all the data about the review.

LET my_reviews = (
    FOR vertices, edges, paths IN 1..1 OUTBOUND "users/6327" reviews
    RETURN {
        name: FIRST(paths.vertices).name,
        review_id: FIRST(paths.edges)._id,
        review: FIRST(paths.edges).review,
        place: LAST(paths.vertices).place
    }
)

LET who_i_follow = (
    FOR v IN 1..1 OUTBOUND "users/6327" follows
    RETURN v
)

LET reviews_of_who_i_follow = (
    FOR users IN who_i_follow
        FOR vertices, edges, paths in 1..1 OUTBOUND users._id reviews
        RETURN {
            name: FIRST(paths.vertices).name,
            review_id: FIRST(paths.edges)._id,
            review: FIRST(paths.edges).review,
            place: LAST(paths.vertices).place
        }
)

RETURN {
    my_reviews: my_reviews,
    who_i_follow: who_i_follow,
    reviews_of_who_i_follow: reviews_of_who_i_follow,
    merged_reviews: UNION(my_reviews, reviews_of_who_i_follow)
}

The first vertex in paths.vertices is the starting vertex (users/6327)

The last vertex in paths.vertices is the end of the path, e.g. who you follow

The first edge in paths.edges is the review that the user made of the place

Here is another more compact version of the query that takes a param, the _id of the user that is 'you'.

LET target_users = APPEND(TO_ARRAY(@user), (
    FOR v IN 1..1 OUTBOUND @user follows RETURN v._id
))

LET selected_reviews = (
    FOR u IN target_users
        FOR vertices, edges, paths in 1..1 OUTBOUND u reviews
        LET user = FIRST(paths.vertices)
        LET place = LAST(paths.vertices)
        LET review = FIRST(paths.edges)
        RETURN {
            name: user.name,
            review_id: review._id,
            review: review.review,
            place: place.place
        }
)

RETURN selected_reviews

Upvotes: 4

Related Questions