# Twitter Follower System Data Model

**URL:** <https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697>\
**Category:** Dgraph Cloud\
**Tags:** kind:question\
**Created:** [April 14, 2021, 2:09pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697 "2021-04-14T14:09:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 14, 2021, 2:09pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/1 "2021-04-14T14:09:17Z")

</div>

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?

```auto

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.

Thanks,

J

---

<div class="post-metadata">

**Author:** ![mrjn](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/mrjn/32/775_2.png) [@mrjn](https://discuss.dgraph.io/u/mrjn)\
**Post date:** [April 14, 2021, 5:39pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/2 "2021-04-14T17:39:57Z")

</div>

This is how it might look like in DQL. You could make this be called via GraphQL.

```auto
{
  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
  }
}

```

---

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 14, 2021, 10:10pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/3 "2021-04-14T22:10:52Z")

</div>

I don’t see where it queries a post at all here, but just **Users** type… Shouldn’t the word **post** be in there somewhere?

J

---

<div class="post-metadata">

**Author:** ![mrjn](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/mrjn/32/775_2.png) [@mrjn](https://discuss.dgraph.io/u/mrjn)\
**Post date:** [April 14, 2021, 10:30pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/4 "2021-04-14T22:30:41Z")

</div>

Ah… sorry. It should be posts instead of creator. I’m updating.

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [April 14, 2021, 10:42pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/5 "2021-04-14T22:42:42Z")

</div>

And don’t forget the GraphQL type dotted notation for the DQL query. 😉

---

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 14, 2021, 11:01pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/6 "2021-04-14T23:01:33Z")

</div>

> [@mrjn](#):
>
> You could make this be called via GraphQL.

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…

> [@amaster507](#):
>
> And don’t forget the GraphQL type dotted notation for the DQL query.

**Users.following.posts**? I am so confused here…

Does this look correct?

```typescript
query {
  queryUsers(id: $user) @cascade {
    following {
      posts(order: { desc: createdAt }, first: 10) {
        id
        title
        description
        createdAt
      }
    }
  }
}

```

And from the other direction:

```typescript
query {
  queryUser @cascade {
    followers(id eq $user) {
      posts(order: { desc: createdAt }, first: 10) {
        id
        title
        description
        createdAt
      }
    }
  }
}

```

Trying to get a general grasps of this.

Thanks,

J

---

<div class="post-metadata">

**Author:** ![mrjn](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/mrjn/32/775_2.png) [@mrjn](https://discuss.dgraph.io/u/mrjn)\
**Post date:** [April 14, 2021, 11:25pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/7 "2021-04-14T23:25:54Z")

</div>

You can embed DQL query in the schema, and trigger it via GraphQL.

[https://dgraph.io/docs/graphql/custom/dql/](https://dgraph.io/docs/graphql/custom/dql/)

---

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 15, 2021, 9:34pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/8 "2021-04-15T21:34:53Z")

</div>

Thanks @mrjn, good to know I can call DQL that way.

Does anyone know if my GraphQL queries look correct?

Thanks,

J

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [April 15, 2021, 10:03pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/9 "2021-04-15T22:03:34Z")

</div>

> [@jdgamble555](#):
>
> Does anyone know if my GraphQL queries look correct?

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.

> [@jdgamble555](#):
>
> > [@amaster507](#):
> >
> > And don’t forget the GraphQL type dotted notation for the DQL query.
> 
> **Users.following.posts**? I am so confused here…

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)

```auto
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:

```auto
{
  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?

---

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 15, 2021, 10:17pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/10 "2021-04-15T22:17:03Z")

</div>

@amaster507

Interesting.

Do you think there is some _feature request_ here that would allow users to avoid **DQL** and get the expected results in **GgraphQL**?

I feel like this is a common use case.

J

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [April 15, 2021, 10:24pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/11 "2021-04-15T22:24:43Z")

</div>

> [@RFC: Nested Filters in GraphQL](http://discuss.hypermode.com/t/rfc-nested-filters-in-graphql/13560):
>
> Motivation There are many requests from the community to add nested filters in GraphQL and it’s also one of the feature which can add more flexibility and value in our GraphQL implementation. Nested Filters like below are not supported in GraphQL . query { queryAuthor( filter: { name: { eq: "Alice" }, or: { posts: { postID: ["0x1", "0x2"] } } } ) { name posts { title } } } Although in DQL this Query is possible using var blocks like below query { post1 as var(…

The idea here is to extend the filters to also filter on edges which would give you what you wanted with a query such as: (this is not yet available)

```auto
query ($myID: ID!) {
  queryPost(
    filter: {
      creator: {
        or: [
          { following: { id: [$myID] } }
          { followers: { id: [$myID] } }
        ]
      }
    }
    sort: { createdAt: DESC }
    limit: 100
  ) {
    id
    name
    description
  }
}

```

---

<div class="post-metadata">

**Author:** ![jdgamble555](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/jdgamble555/32/7503_2.png) [@jdgamble555](https://discuss.dgraph.io/u/jdgamble555)\
**Post date:** [April 15, 2021, 11:06pm UTC](https://discuss.dgraph.io/t/twitter-follower-system-data-model/13697/12 "2021-04-15T23:06:39Z")

</div>

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):

1. **Search by:** get User.following.posts where User.following.id = $userId
2. **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?

J
