Modeling the Twitter Follower system is one of the biggest problems with noSQL. I assume this could be done effortlessly in DGraph. The biggest problem, specifically, is querying all posts (tweets) by users you follow sorted by createdAt descending.
So, how could this query theoretically be done?
type User {
id: ID!
email: String!
following: [User] @hasInverse(field: followers)
followers: [User] @hasInverse(field: following)
posts: [Post] @hasInverse(field: creator)
}
type Post {
id: ID!
name: String!
description: String!
createdAt: DateTime
creator: User!
}
1.) Does this schema look correct?
2.) How would the query look (I guess forward and backward with @cascade) ?
a) query posts by all current user’s followers sorted by createdAt desc
b) query posts where user following equals current user sorted by createdAt desc
I am not quite sure how to do a) and b) assuming the schema is correct.
This is how it might look like in DQL. You could make this be called via GraphQL.
{
var(func: uid(my-id)) {
following {
p as posts # Store all the posts created by your followers.
@filter(gt(createdAt, "2021-04-07"))
# Can optionally filter the posts by createdAt, to only pick posts within the last 7 days or so.
# Basically, idea is to reduce the number of posts picked up.
}
}
res(func: uid(p), orderdesc: createdAt, first: 100) {
id
name
}
}
How would I make the GraphQL query? Unless I am using lambdas, I can’t call dql in cloud dgraph via GraphQL. Please correct me if I’m wrong, or there would be a security risk…
Users.following.posts ? I am so confused here…
Does this look correct?
query {
queryUsers(id: $user) @cascade {
following {
posts(order: { desc: createdAt }, first: 10) {
id
title
description
createdAt
}
}
}
}
I believe they will work, but don’t think it is going to do exactly what you expect. And by that I mean that the ordering of the posts happens in each list for each user, but not an ordered list of all the posts together. To do that you would have to do DQL inside of GraphQL like Manish said.
Sorry for the confusion. Let me try to quickly explain.
Your GraphQL schema is not exactly the same as the DQL schema. There is some “magic” that the API does for you that you do not have to be aware of until you start doing some DQL queries. Because when you start using DQL, you must understand how the GraphQL schema gets mapped to the DQL schema. And that is done by “type dotting the predicates”.
That sounds somewhat complex but is actually really simple, especially if you are not using any interfaces.
The GraphQL schema you provided above gets mapped to the following DQL types (leaving out the predicate definitions themselves)
type User {
User.email
User.following
User.followers
User.posts
}
type Post {
Post.name
Post.description
Post.createdAt
Post.creator
}
Notice that User.id and Post.id was not present above. That is because they get translated to uid directly and are not type dotted renamed.
Here is a the correct DQL query for your GraphQL types that @mrjn tried above:
{
var(func: uid(my-id)) { # replace my-id with your user id.
User.following {
p as User.posts # Store all the posts created by your followers.
@filter(gt(Post.createdAt, "2021-04-07"))
# Can optionally filter the posts by createdAt, to only pick posts within the last 7 days or so.
# Basically, idea is to reduce the number of posts picked up.
}
}
res(func: uid(p), orderdesc: Post.createdAt, first: 100) {
id
Post.name
}
}
See hos that every field was translated to a dotted type?
The nested filters make sense, so +1 from me for another use case on the feature request.
However, I don’t understand your query. You’re saying get followers or following by the userId, which are two completely different things.
The goal here is to get the same results in two different ways (I am learning here, and obviously one way will be quicker than the other). Your query will mix the follower’s post and the following’s post, which doesn’t make sense to me…
What I would want (sorted by createdAt desc):
Search by: get User.following.posts where User.following.id = $userId
Search by: get User.followers.posts where User.id = $userID
I would think both of these would get the same results. It looks like the dql above is using the first option…
So, if I go the 2nd option, do I still need nested filtering?