Using external identifiers with DQL fails

I set up a new type:

type Platform @auth(add: { rule: "{$ROLE: { eq: \"ADMIN\" } }"},
update: { rule: "{$ROLE: { eq: \"ADMIN\" } }"},
delete: { rule: "{$ROLE: { eq: \"ADMIN\" } }"})  {
    platform: String! @id @search
    num: Int!
}

I made sure I have no instances of this type in the database and created a new one with a mutation.

mutation MyMutation {
  addPlatform(input: {platform: "microsoft", num: 10})
}

When I look in data explorer, I see it still created a UID outside of what I specified.

The problem I am running into, when I try to update it via DQL

updatePlatform = {
  "uid" : "microsoft",
  "Platform.num": 10000
}
...
mutation = txn.create_mutation(set_obj=updatePlatform)
...

I get an error details = "strconv.ParseUint: parsing "microsoft": invalid syntax"

But if I use the UID 0x2981a that was auto generated, it works fine.

My understand is if I use @id instead of ID, it would use my own data as the unique ID.

I did find this thread which lends me to believe this is not possible with DQL.

Yeah, you can’t use it like that. You can’t have the all* goodies of both worlds(DQL and GraphQL are totally different things - BUT, you can use both! :stuck_out_tongue: ). You can try Upsert Block tho. Or stick to GraphQL.

1 Like

I need to use both GraphQL and DQL due to limitations of GraphQL on Slash (atomic transactions).

I’m just starting to grasp this statement “DQL and GraphQL are totally different things”.

Been banging my head thinking they are just two different ways to access the same db.

Sure you can, you just have to have a very deep understanding of how the two work together.

That is the solution to this.

This is still a true statement. They are two endpoints over the same Badger key-value store.

All requests to the GraphQL endpoint get rewritten in Go functions to DQL. If it can be done in GraphQL it can be done in DQL. But the other way is not necessarily true. If it can be done in DQL it might be possible in GraphQL, depending on if the GraphQL syntax specification supports it, and if the engineering team has implemented it in the rewriting functions.

Upserts are coming to GraphQL, which you already commented on that post. But truth be told, upserts are already in GraphQL in a way, just not in a INSERT or UPDATE single request syntax. The GraphQL update* mutation gets rewritten to DQL upserts. This is how it is possible to have an update statement based on a filter and not only a uid.


This is correct. EVERY node will have a uid whether that uid is exposed to the GraphQL endpoint or not.

Update:

It is possible to change the GraphQL schema to expose the uid (Just add a field with the ID scalar), change the @id to a different field (just put it on a different field, and mutations will be updated to then use that other field), and coming soon :wink: have multiple @id fields within a single type. Right now it is possible to even expose both the ID and have a xid using @id: https://dgraph.io/docs/graphql/schema/ids/#combining-id-and-id


To do this in DQL use:

{
  "query": "{ v as var(func: eq(Platform.platform, \"microsoft\")) }"
  "set": {
    "uid": "uid(v)",
    "Platform.num": 10000
  }
}
2 Likes

You “sort of can”, but not for real. GraphQL doesn’t supports RDF syntax. e.g: Blank Nodes. Using custom DQL in GraphQL isn’t a “graphql feature”. Is Dgraph giving the user the opportunity to use DQL directly on schema instead of coding his own client. My point is, you can’t have all DQL features in GraphQL “natively”. Or use GraphQL ID or @id in DQL.

BTW, I have to state that this is wrong even in DQL. I know that looks logical. But isn’t valid. The UID key accepts only uint64(or uint64 in variables) and blank nodes. Blank nodes are tied to the transaction level. So if you use _:microsoft a second time, it won’t be the same entity as before. It will be a new one. So it is not a fixed identifier. Only the uint64 is a fixed identifier.

In GraphQL you have the id features that might set “Microsoft” as an identifier. But that won’t work in DQL. And to work in DQL using Upsert block, you have to query for that custom identifier recorded in the entity and then update it. It is a totally different way to do the same thing.

The logic behind GraphQL is complex. You would have to read the core code to replicate the exact in DQL. But that won’t work well, cuz DQL won’t do everything. In the GraphQL core code, there’s some logic in going. Which isn’t DQL’s harvest. So you would have to create your own business logic replicating the GraphQL’s code. Cuz not everything can be done with just DQL. And you know that :stuck_out_tongue: .

That will be good. But you see? it is necessary a bunch of code in the core to make it happen. It doesn’t just depend on DQL.

1 Like

@billybobthorton To add to what @verneleem wrote, Platform.platform is your @id string predicate that you can lookup for update, and updating nodes uses upsert blocks exactly like the one @verneleem shared.

Okay, to be clear with my comment. I think that it attracted a little confusion with the interpretation that this can generate.

cc: @dmai

When I say “You can’t have the goodies of both worlds” I’m just saying that not everything done in GraphQL can be replicated purely with DQL and vice versa. Some features require business logic that pure DQL does not provide. Luckily, this need is met using Upsert Block.

However, you can use both. I didn’t understand why someone would interpret it as “you can’t use both”. Sorry if that is the strongest interpretation that can be extracted from what I wrote. But that is not my intention.

They are sister languages, but distinct. I hope this clarifies my comment.

Yes, there are two ways for you to access the same DB (DQL and GraphQL). And I usually tell(a little off-topic, but not so much) DB admins that if you use GraphQL, keep using GraphQL in your applications and use DQL only for administrative and correction activities. For DQL has no auth for example - unless you build your own (or Dgraph provides a way in the custom DQL feature to use GQL auth - that I’ve been told it’s not yet supported). A malicious user could exploit this in your application if you give him access to pure DQL without a restriction. (The user could not ever do SQL injection like, but you opening to opportunities). Only use DQL behind a business logic. Okay?

If you have an application build in DQL with auth and also provide GraphQL with auth for example. The better. So you have a protected DB on both fronts.

Cheers.

2 Likes

the joys of textual only communication. Thanks @MichelDiz for adding extra clarification, many knew what you meant as you are one of the most experience in the community. Sometimes these advanced topics are hard to explain only in textual messages back and forth with massive opportunities for misunderstandings.

2 Likes

Yeah, text-only communication is hard, and I have a bias in the community - thinking that everyone else (and in general they do, which makes me impressed and happy to see) have done some homework by reading, searching, searching docs, and even searching old conversations(sometimes reviving some pretty old ones LOL) - so my bias relies on thinking that they understood what I said, cuz I see that they have some notion, based on what they wrote. But I expect that someone complains to give me the opportunity to notice where I lack. It’s only by making mistakes that you learn something for real.

I’m always pleased to present Dgraph to new ones. But if they show up as an experienced user. I erroneously oversimplify.

1 Like