MB175
March 9, 2023, 2:32pm
1
Hi,
I want to set a unique constraint on containerId so only one Node per ID is created
I tried upsert and indexes with dgo, nothing works?
Can this be done?
[{
"name": "test1",
"parent": {
"containerId": "parent1"
},
"containerId": "container1"
},
{
"name": "test2",
"parent": {
"containerId": "parent1"
},
"containerId": "container2"
}
]
Currently mutating with JSON like this:
mu := &api.Mutation{
CommitNow: true,
SetJson: json,
}
response, err := s.DClient.NewTxn().Mutate(context.Background(), mu)
if err != nil {
log.Fatal(err)
}
MichelDiz
(Michel Diz)
March 10, 2023, 3:15am
2
Where is the query? I think you are not using Upsert correctly. You should have a query and also use variables. Maybe you have stepped into the Upsert Directive docs. Which is not the same as Upsert Block. See the examples bellow.
https://dgraph.io/docs/dql/dql-syntax/dql-mutation/#upsert-block
https://dgraph.io/docs/dql/mutations/uid-upsert/
MB175
March 10, 2023, 10:08am
3
I must admit I don’t even understand the docs my example above works perfectly fine,
for example, if I create the parent beforehand and add a uid field to the parent with the uid of the node I can achieve what I want.
In general, I was wondering if there is a way to avoid that initial creation of the parent node because its much more effort to inject an uid field in the json array at every parent object.
I was wondering if it might be possible to set a constraint on the containerId which would lead dgraph to automatically resolve the fact that there should be only one node with that exact containerID
MRW
March 13, 2023, 6:04pm
5
MB175:
In general, I was wondering if there is a way to avoid that initial creation of the parent node because its much more effort to inject an uid field in the json array at every parent object.
I was wondering if it might be possible to set a constraint on the containerId which would lead dgraph to automatically resolve the fact that there should be only one node with that exact containerID
You need to use the @id directive on the field you want to act as a unique key.
For example, with your data:
type Container {
containerId: String! @id
name: String # must be nullable, don't use String! here
parent: Container
}
Now, inserting/upserting the following
{
"name": "test1",
"parent": {
"containerId": "parent1"
},
"containerId": "container1"
},
will produce two nodes, one with all this data and one with just the containerId “parent1”.
Then, inserting/upserting
{
"name": "test2",
"parent": {
"containerId": "parent1"
},
"containerId": "container2"
}
will create one new node, and link the parent field to the existing Container with containerId “parent1”.
However, the “parent1” Container still only has a containerId field, it does not have a name – you need to upsert that information separately if needed.
In any case, this approach allows you to create unique nodes per containerId, and it also automatically creates an empty-ish parent node, so you don’t need to inject any UIDs anywhere, and can manage your data completely from business key land.
amaster507
(Anthony Master)
March 13, 2023, 9:55pm
6
That only works with the GraphQL schema and only then still if you only use the /graphql endpoint API. It does not cross over the constraint to DQL
This does seem to be on the roadmap for sooner than later. They said they do want to build it from dql layer up.
opened 12:49AM - 26 Aug 22 UTC
kind/feature
area/graphql
community
Related to [this issue](https://github.com/dgraph-io/dgraph/issues/8176) for ref… erence.
# Keys
**Composite Key** - has more than one attribute
**Compound Key** - a specific composite key where both attributes are also foreign keys
## [PK (Primary Key)](https://www.w3schools.com/sql/sql_primarykey.asp)
- _Right now, we can do this:_
### Single PK or @id (external id)
```graphql
type User {
username: String! @id
name: String!
}
```
### SQL
```sql
ADD PRIMARY KEY(username)
```
___
### Composite PK or @id
```graphql
type User {
username: String! @id
email: String! @id
}
```
### SQL
```sql
ADD PRIMARY KEY(username, email)
```
___
## [Unique Keys (Unique)](https://www.w3schools.com/sql/sql_unique.asp)
- **What we need to be able to do:**
### Single Unique or @unique
```graphql
type User {
id: ID! @id
username: String! @unique
name: String!
}
```
### SQL
```sql
ADD CONSTRAINT UNIQUE (username)
```
___
### Multiple Uniques or @unique
```graphql
type User {
id: ID! @id
username: String! @unique
email: String! @unique
}
```
### SQL
```sql
ADD CONSTRAINT UNIQUE (username)
ADD CONSTRAINT UNIQUE (email)
```
___
### Composite Uniques or @unique
```graphql
type User @unique(fields: ["firstName", "lastName"]) {
email: String!
firstName: String!
lastName: String!
...
}
```
### SQL
```sql
ADD CONSTRAINT UNIQUE (firstName, lastName)
```
## Compound Keys - composite keys on foreign keys or nested fields
```graphql
type Book {
id: ID!
name: String!
...
}
type User {
id: ID!
name: String!
reviews: [Review]!
...
}
type Review @unique(fields: ["reviewer.id", "book.id"]) {
reviewer: User!
book: Book!
createdAt: DateTime!
}
```
### SQL
In SQL, there would be a composite pk on the junction table [book_id_fk, user_id_fk, created_at]:
```sql
ADD PRIMARY KEY(book_id_fk, user_id_fk)
```
So theoretically, there should be a unique key on reviewer.id and book.id. This should also be possible for one foreign key, although I can't think of an example.
___
**UPDATE:** 11/2/22 - The @unique (not the @id) should be able to be null.
```graphql
type User {
id: ID! @id
username: String @unique // no ! in input
email: String! @unique
}
```
Referring to [this post](https://github.com/dgraph-io/dgraph/issues/8117), you should also be able to get multiple fields based on their **COMPOSITE** primary or unique key(s) as well as [individual unique keys](https://dgraph.io/docs/graphql/schema/ids/), which is how it currently works:
```graphql
query {
getUser(username: 'jdgamble555', email: 'someone@something.com') {
username
...
}
}
```
So we really have a few feature requests here:
1. Possibly rename @id to @unique
2. Allow top level @unique directive for multiple "composite" unique constraints
3. Allow "composite" unique constraints on nested fields (only one level), same as junction table
4. Make sure you can search with "get" for the composite fields
5. Allow nullable unique, as "no value" should not break the constraint
#2 is the main request here
___
- The GraphQL schema should fail if someone tries to add this directive on a field where there are "non unique" values.
- Some of this should be build on the [DQL level up](https://github.com/dgraph-io/dgraph/issues/8408), which is a different feature request. This should be implemented first.
J
___
Just for more reference - https://github.com/outcaste-io/issues/issues/26
J
MB175
March 14, 2023, 9:12am
8
can’t I do an upsert query in DQL by indexing over containerId making a lookup of it keeping the uid and patching the entity with the correct uid ?
MB175
March 14, 2023, 9:19am
9
Is there any examples how this could be accomplished in DQL with the GO-Client, I have some approaches but a best practice implementation would be nice
MichelDiz
(Michel Diz)
March 14, 2023, 5:20pm
10
Yes. Read the link I’ve shared. The response is there. " Running an Upsert: Query + Mutation"
If you need a condition running-conditional-upsert .