Unique Constraint on string

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

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/

I must admit I don’t even understand the docs :smiley: 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

Use this

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. :grinning_face_with_smiling_eyes:

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.

J

1 Like

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 ?

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

Yes. Read the link I’ve shared. The response is there. " Running an Upsert: Query + Mutation"

If you need a condition running-conditional-upsert.