Friends vs. Considered Friends using @hasinverse

Hi,

I have this schema in my database.
The reason for applying has inverse on friends is that person ‘a’ might consider person ‘b’ a friend while the latter doesn’t consider ‘a’ as his friend.
In other words, having user ‘b’ I want to know who considers him as their friend.

type Person {
    personID: ID!
    name: String @search(by: [term])
    friends: [Person] @hasInverse(field: friend)
}

Now, my problem is how I can insert data using graphql with this schema?
I need the equivalent of the following data in graphql±:

{
    "set":[
        {
            "uid": "_:p1",
            "dgraph.type": "Person",
            "name": "John",
            "friends": [
                {
                    "uid": "_:p2"
                },
                {
                    "uid": "_:p3"
                }
            ]
        },
        {
            "uid":"_:p2",
            "dgraph.type":"Person",
            "name": "Doe"
        },
        {
            "uid": "_:p3",
            "dgraph.type": "Person",
            "name": "Jane",
            "friends": [
                {
                    "uid":"_:p1"
                }
            ]
        }
    ]
}

Also, how I should implement such a query (is there anything similar to ~ in graphql±)?
my query in graphql± is:

{
   considered_friends(func: eq(name: "Doe")){
       name,
       considered_friend: ~friend {
           name
       }
   }
}

the result is John

1 Like

You will need to either remove the hasInverse and just add friends as one directional, or…

Make a linking node that keeps extra information about the friend relationship. There are many different ways that this could be done, here are two possibilities:

  • A friend node that has a requested and confirmed field to track who made the requested friendship and if it was confirmed.
  • Separating it into two fields on the Person, friendReq and friends. A request gets sent over to the friendReq until it is confirmed and then it gets deleted from friendReq and created as friends.

About this point. If you are inserting data via DQL. You should add a “prefix” to your DQL mudation. e.g:

{
            "uid": "_:p1",
            "dgraph.type": "Person",
            "Person.name": "John",
            "Person.friends": [
                {
                    "uid": "_:p2"
                },
                {
                    "uid": "_:p3"
                }
            ]
        },

Dgraph’s GraphQL has this prefix for each entity. But is better you do it via GraphQL itself.

1 Like

Hi,

Thanks for your response.
I would be happy to know if there is an equivalent implementation\solution to my scheme and query in DQL (grpahql ±) by using Graphql.
I understand that I can create two edges, one for each direction, but I believe that one connection with @reverse \ @hasinverse will be better in this use case (correct me if I’m wrong).

Thanks

How would you do that in GraphQL, I can’t find an example in the docs that insert data with connections to entities that are created during the same mutation

Two edges are better for relation logic. For example, you wanna implement the logic of “add, accept and friends”. Using the reverse index, you don’t have this logic. Cuz, every single new relation, in a reverse case, will have both directions.

For me, the reverse index is useful for other cases, not relational logic.

You don’t need to “prefix” your edges via GraphQL. That’s the “nature” of Dgraph’s GraphQL. It adds this prefix in relation to the Type itself. But, if you are working in DQL and wanna use the GraphQL feature, you should follow this pattern.

BTW, I fear that didn’t get your question entirely. The part of connections, connections on GraphQL are done based on the Schema. If your GQL types have connections, this should be reflected in your mutations.

Ok I understand your point.
can you give an example of a use case that you would use @reverse

It depends on the data model. In general reverse directive is useful to “sneak peek” incoming relations. You can also use this to do complex filtering in multiple blocks. The reverse avoids round trips on the query. If they didn’t exist finding incoming edges would be hard and use a lot of resources (CPU and RAM).

Another example, traversing the relations with recurse, is pure magic. You can find long relations with almost zero effort. Imagine a family tree. You can expand the past of a family tree easily with reverse and recurse.

Great thanks for your answers.

Last question: Is it fine to define the scheme in GQL and use DQL for querying or mutating the data?
I saw some features of the GQL scheme that are not supported yet in DQL such as the @auth directive and on the other hand some of the functions for querying data are defined only in DQL

Totally fine. As long you use the GraphQL pattern (I mean, the data modeling) you are good to go. And personally, even if you don’t wanna use the GraphQL, I think that the kind of “namespacing” it has, is very useful for performance if you have a really huge amount of data. Separate the predicates based on the Type is really useful.

Yeah, those features 99% for sure won’t come to DQL. Cuz the implementation in DQL would be totally different from GraphQL. Some features from DQL probably won’t ever be implemented in GraphQL. Cuz it depends on the GraphQL Foundation to implement in the specs. Dgraph is part of the foundation, but the majority of Dgraph’s features are database related. And GraphQL was created to be “data agnostic”. So we can ask them to put our specs in their specs as no other DB or API would ever implement it.

Ok :grinning:

So to wrap it up I want to check that I get @revers driective right.
I designed a new data model and I would be happy to hear what you think about the usage of the @revers directive in it:

type repository{
    branches: [Branch!]
    members: [User!] @hasInvers {field: member_of}
    owned_by: User!
    teams: [Team!] @hasInvers { field: work_on}

}

type user {
   lives_at: Location

   works_at: Location

   member_of: [Repository!]

   owner: [Repository!]! @hasInvers {field  owned_by}

   part_of: [Team] 
}

type team{
    members [User!] @hasInvers {field part_of}
    work_on: [Repository!]!
}

would you use also the @reverse directive on the locations where the user work and live?

This schema you have shared is GraphQL. GraphQL doesn’t have @reverse index. I think I have mentioned that the two things are totally different.

So, Location is another type, right?

Probably the missing characters are typos. This should look like

members: [User!] @hasInverse(field: part_of)

DQL reverse is useful for complex filtering, kind of “analysis of dataset” and other personal usage. So, just use it if you know you gonna need it.

Ok, I assume I understand from other conversation the difference between the two.
I think I will use only @reverse directive on types that I need to investigate from both directions.
Forr example if a user has the connection lives_at to a Location type I think I would use the reverse to find all users who live in that location right?
I sent you a scheme in GQL but I probably translate it to DQL now that I understand the differences between the directives and capabilities of the languages.

yep, that one useful way to do it.

cool