Facets in GraphQL

If we use @dgraph directive with facets, it will work the same way as we described @facets directive.
I am just providing the schema examples here:

UID

type Person {
    name: String!
    pet: Animal
}
type Animal {
    id: ID!
    name: String!
    color: String
    petClose: Boolean! @dgraph(facet: "close")
    petSince: DateTime @dgraph(facet: "since")
}

We don’t need to provide a field name in this case and will assume that whenever type Animal is referenced.

[UID]

type Person {
    name: String!
    pet: [Animal]
}
type Animal {
    id: ID!
    name: String!
    color: String
    petClose: Boolean!  @dgraph(facet: "close")
    petSince: DateTime @dgraph(facet: "since")
}

Similarly, for this case also, we don’t need to provide a field name and will assume it whenever type Animal is referenced.

Scalar

type Person {
    name: String!
    pet: String
    petClose: Boolean! @dgraph(facet: "close",field: "pet")
    petSince: DateTime @facet(facet: "since",field: "pet")   
}

[Scalar]

Similarly for the scalar list, if we are going to represent facets as lists in the same type.

type Person {
    name: String!
    pet: [String]
    petClose: [Boolean]   @dgraph(facet: "close",field: "pet")
    petSince: [DateTime] @dgraph(facet: "since",field: "pet")
}

Hi, sorry for barging in, but I think this (Traverse on different types) is a good example of a usecase where facets could shine in GraphQL (assuming we get the sorting and first: thing of the facets fixed)

In that post the OP wants to compute a path, and a graph database should be able to do that trivially, without resorting to the kinds of data structure that the OP has created. But because of the limitations of GraphQL, the extended tuple data structure (i.e. encoding edge data into a vertex, leaving the edges unlabelled) was used .

2 Likes

Maybe this is something I can be more onboard with

Ok, fair enough, so I can move the facet into a type and do a more natural modelling. Great!

For Scalar and [Scalar], I don’t like it as much … because

For me, this is technically ok:

it gives you a way to export a Dgraph facet into a GraphQL type, sure, but I wouldn’t do that modelling: why is petClose a property of a person? Regardless of how it’s implemented in the underlying database, I’d want to model this more like

type Person {
    name: String!
    ownsPet: PetOwnership
}

type PetOwnership {
    pet: String
    close: Boolean! 
    since: DateTime 
}

or, if pet is really worthy of it’s own type, put pet into it’s own type and also model the pet ownership relation.

So I’d always go with the UID option and model it that way. But I can’t here cause the UID options and Scalar options are different in their GraphQL representation… so if I did have facets on scalars in my DB, then I wouldn’t be able to get the modelling I want … but then I probably wouldn’t have have done it that way anyway, so maybe I don’t mind? In the end, I’d like to be able to model scalar facets the ‘right’ :slight_smile: way, but maybe this works first up.

1 Like

Very interesting read - where did things land in the end?

4 Likes

Any update on this?

Neo4J’s GraphQL adapter solves relationship properties (facets) by creating an extra level of nesting between the parent and the child. I think this is the only way that will work with complex graph structures.

type Movie {
  title: String
  year: Int
  ratings: [Rated]
}

type User {
  userId: ID
  name: String
  rated: [Rated]
}

type Rated @relation(name: "RATED") {
  from: User
  to: Movie
  rating: Float
  created: DateTime
}

More information:

2 Likes

Hi all, this feature is being worked out and we will have it soon.

2 Likes

Hi, Is there a PR we can track?

Hi,
There is no PR to track currently. This is assigned to me in current sprint and is being worked upon. Last 2 weeks we were busy with 21.03 bug fixes and testing and didn’t get time for this.

1 Like

I have kind of been thinking in the interim, we could do something like that with one caveat:

type Movie {
  title: String!
  year: Int!
  ratings: [Rating]
}

type User {
  userId: ID!
  name: String!
  ratings: [Rating]
}

type Rating {
  id: String! @id
  user: User! @hasInverse(field: ratings)
  movie: Movie! @hasInverse(field: ratings)
  rating: Float!
  createdAt: DateTime
}

Basically, when we would create a rating, we would create the id as user_movie forcing a unique (composite) identifier based on the relationship.

This may even be better than using facets. I am wondering if there is even a speed difference between a facet and a new type, considering it is all stored as a triple in the database anyway.

J

From what I understand adding the facets to graphql (and hence into generated filters) would allow you to mutate/delete with the capability of filtering based on and/or altering the relationships much easier (removal if you’re deleting the object) compared to having a type defined for that relationship (since types are not searchable or added to filters), correct? Would neatly give a work around for a lot of the requests for nested filters/cascading deletes for many use-cases if that’s the case.

@rajas A couple of things I was thinking about:

J

Hi @rajas , is there any update on adding support for facets in the GQL interface? It’s something I’m excited abiut

I beleve @rajas opened a PR for this feature a while back: Feat(GraphQL): Add support for facets in GraphQL (Schema changes) by vmrajas · Pull Request #7855 · dgraph-io/dgraph · GitHub

Unfortunately, @rajas closed it 7 days ago. @rajas I didn’t find any explanation following the review on why the PR closed. Could you share more?

@rajas Any news here? Should we be expecting this in the upcoming release?

The PR mentioned here was just for schema changes. This is an involved undertaking, we don’t have a timeline for this feature. I’d recommend running DQL queries / lambdas to get facets from GraphQL.

https://dgraph.io/docs/graphql/custom/dql/#sidebar