Support multiple unique fields in dgraph GraphQL

Also +1 on this feature. Feels like a basic thing to have.

1 Like

Hi, +1 for this feature.

Does the unique field will also support unique constraint based on the filtering on a given field ? For example, if we want to have unique label names per company, we could say

type Label {
  name: String! @unique(f: "company") 
  company:  String! @search
}
1 Like

Hi @dtrckd, as of now we are just allowing the @id field to be applied on multiple field in a type and every field with @id directive will be unique over the nodes of that type.
RFC: RFC: Allow multiple unique fields in graphql schema

1 Like

When you say “as of now,” what version of dgraph is “now?”

Hi @oising,

Welcome to Dgraph Community !!

Multiple ID fields feature is in planning stage and is not available in any Dgraph versions. The related RFC is RFC: Allow multiple unique fields in graphql schema .

The “as of now” refers to what is being considered in RFC and does not refer to any existing Dgraph version.

If you want to to know the latest version of Dgraph, it is 20.11 . You may find more details here, Release Notes v20.11.0 - Tenacious T'Challa .

1 Like

@rajas I just wanted to give an example of a perfect use case for this. While you are building graphql facets, there is a need for this in basic graphs.

Let’s say a user reviews a movie, there should be only one review:

Obviously, it would be better to have a unique restraint like in SQL:

ALTER TABLE `Rating` ADD UNIQUE `unique_index`(`user`, `movie`);

J

Hi @jdgamble555, support for multiple @id’s is already added in graphql and available in 21.03. In addition to that we also added some more features to @id fields like mutable and nullable @id fields which will be avaliable in 21.07. follow the below link for more details.
RFC: RFC: Allow multiple unique fields in graphql schema
PR: Feat(GraphQL): This PR allow multiple @id fields in a type. by JatinDevDG · Pull Request #7235 · dgraph-io/dgraph · GitHub

Hi @JatinDevDG.

I guess multiple @id nodes are the same thing as a unique restrain on two fields if you think about it.

Thanks, I didn’t realize that!

UPDATE 5/16/21:

What I was talking about here are composite id fields:

J

Hi @jdgamble555, multiple @id fields doesn’t guarantee unique constrain on a combination of two fields.
It just means that we can have multiple @id fields in a type. And every such field value will be unique across all the nodes of that type. But other @id fields or normal fields in a type can have that value. ​

Example :
type {
​t1: String @id
​t2: String @id
​t3: string
}

Below is the valid state according to @id rules but it doesn’t guarantee unique constraint on two fields.
node1:-
t1-“Alice”
t2-“Bob”

node2:-
t1-“Bob”
t2-“Alice”

We have a ticket for composite @id fields that will allow us to have a unique constraint on two or more fields and we will try to add it soon.
see this:
RFC: Allow multiple unique fields in graphql schema
Composite @id fields

2 Likes

Hi Jatin, I am a new user (2 days old), and was trying out dgraph.

on trying to insert duplicate values for fields which have ‘@id’ directive, i was expecting dgraph to throw error, but it seems it allowed it.

## curl -X POST localhost:8080/admin/schema --data-binary '@graph/schema.graphql'
type TransactionType {
    name: String! @id @search(by: [term])
    slug: String! @id
}

Note:

  1. noticed that in schema, the TransactionType.name field has index ‘hash’ as well as ‘term’. It seems ‘hash’ is added because it has constraint @id.
## curl -X POST 'http://localhost:8080/mutate?commitNow=true' --data-binary '@graph/insert.graphql' -H'Content-type: application/rdf'

{
 set {
        _:x  <dgraph.type> "TransactionType" .
  	_:x  <TransactionType.name> "Debit" .
	_:x <TransactionType.slug> "debit" .
	
	_:a <dgraph.type> "TransactionType" .
	_:a <TransactionType.name> "Debit" .
	_:a <TransactionType.slug> "debit" .
 }
}

Note:

  1. I was expecting this transaction to fail due to @id constraint on nodes TransactionType.name and TransactionType.slug

thanks
Rajat Jindal

Hi @rajatjindal , Welcome to the Dgraph community !!
@id is a graphql concept and works only in graphql layer. You posted a Graphql schema but the given mutation is of type DQL(Dgraph query language) and is on dgraph endpoint.
http://localhost:8080/query —DQL query endpoint
http://localhost:8080/mutate --DQL mutation endpoint

You need to use GraphQL mutation in order to use the @id feature and that will be on
http://localhost:8080/graphql --GraphQL query/mutation endpoint
see graphql docs for more details
https://dgraph.io/docs/graphql/

@JatinDevDG - Are there plans to add @id to the DQL layer?

Hi @eugaia, no @id fields are completely GraphQL features that are implemented using DQL upsert mutations. And there is no plan to add it in DQL as of now because same effect can be achieved upsert mutations.

Basically, the @id field is just a normal field but while adding or updating it we make a query to check whether there is a node with the same value already, exist or not. If you want to have such behaviour, you need to write your own upsert block.
https://dgraph.io/docs/mutations/conditional-upsert/

1 Like

@JatinDevDG - Thanks.

Is there a way using conditional upserts to perform the same action on every predicate of the same name in say a ‘set’ operation?

e.g. You’re if you’re importing 10 million RDF triples about 1 million nodes, is there a way using conditional upserts to automate the checking of every predicate ‘myID’ to check for uniqueness, or would you need to generate a separate upsert command for each node to check that the ‘myID’ field value is unique?

I guess that’s not possible while importing. DQL guys will tell more.
@MichelDiz any idea?

1 Like

Thanks. I have a second question too:

Assuming we have two parallel upsert requests to insert a value to the myID predicate that both want to set the same value ‘someID’. If there’s a race condition such that both of them see that there is no other node with a myID value set to ‘someID’ as part of the query block of the upsert, when one of those transactions commits, will the other transaction automatically commit without checking the myID predicate again for a value ‘someID’ or will the value be checked for again before committing (to guarantee uniqueness of myID at the point of committing, not just the point of querying)?

Thanks.

Not while importing. But there is a feature in Live loader related to XIDs(Blank nodes, unique identifiers). If you use it, it will create an upsert block based on the identifier in the RDF. This is a bit different but provides uniqueness via live loader.

You can use the directive @upsert which guarantees these concurrent(Conflicts) behaviors. Read https://dgraph.io/docs/howto/upserts/#upsert-procedure

2 Likes

@MichelDiz - Thanks.

1 Like

just FYI - i’m messing around on a starter/free instance of dgraph cloud and this feature is not available there yet. adding two @id generates this error:

… but a type can have only one field with @id. Pick a single field with @id for type …

Hi @RickSalmon , Welcome to Dgraph community!!
This feature is available in 21.03 release and cloud is currently using 20.11.
We are upgrading cloud to 21.03 that will be done in 2-3 weeks.