BUG: DQL doesn't connect nodes

Version: v21.12.0

Adding an entry with GraphQL automatically connects the nodes. DQL doesn’t do that!!!

Is this a BUG?

Not sure what you mean. Can you be more specific? What is the bug?

Adding something with GraphQL automatically connects the hasInversed nodes. DQL doesn’t.

I guess there is a good reason for that, but I would like to know how to write a mutation that connects also the nodes in DQL

GraphQL and DQL are two “distinct realms”. GraphQL does everything automated because it is a separate application that aims to automate your API. Based in your schema Dgraph’s GraphQL implementation creates all resolvers and logic to “resolve” your datamodel.

DQL is like “MYSQL”, it’s a database language. And we don’t have all the features that exist in GraphQL. Well, they are different things. Since you are using GraphQL, stick to it. Don’t try to do anything in DQL if you don’t know what might happen. Doing this without having full knowledge of DQL can be dangerous and break your entire GraphQL structure.

DQL is like “RAW”, “work by hand”, while GraphQL is logic automation. You already have more than 90% of the work done that you would have if you were to do everything by hand. Coding GraphQL resolvers for other databases is Herculaneum work. Using Dgraph’s GraphQL saves you valuable time.

And, no, it is not a bug. Just different things.

I’m assuming you are using JSON for DQL mutation.
How to “connect nodes” is explained at
https://dgraph.io/docs/mutations/json-mutation-format/
you can totally send a mutation that will create two nodes that are “connected”.
Note that “connected” in Dgraph just means that an entity has a predicate to a uid (an other entity).
Happy to help if you have a sample of what you want to add in graph using DQL mutation…

@MichelDiz We can’t use graphQL for that matter because of a million reasons that are not related to this issue.

Can you let me know how I can add an entry with and connect the nodes using DQL?

Sure, you can use Upsert Mutation.

The logic is like this.

You have a block to search for the target and a block to mutate the logic. For example, you wanna link two persons. You gonna find then in the query block. And link them via variables in the mutation block. That’s the only way.

See https://dgraph.io/docs/mutations/upsert-block/#sidebar

Thanks @Raphael for the response. I am still failing to see how to connect the nodes from the documentation you posted. I am literally doing exactly what the documentation says, but the nodes still don’t connect. Instead, the DB creates a duplicated node without any connections.

Why do I have to do another query to find the uid of the object I want to connect to since I already know the uid?

For example:

I have two types. A and B

I want to add an A{myB: {uid: “0x1234”}}. B with 0x1234 already exists. Why do I need to query Bs with 0x1234 uid? What information I will get? I already know the uid.

That doesn’t make any sense.

Also. What if my A has many fields that are connected to other nodes. How many queries I have to make more?

Okay, if you know the UID. And always will. You just have to do

RDF Mutation

<0x1> <linkTo> <0x2> .

JSON Mutation

{
  "set": [
    {
      "uid": "0x1",
      "linkTo": [
        {
          "uid": "0x2"
        }
      ]
    }
  ]
}

That’s it.

See the doc share by Raphael https://dgraph.io/docs/mutations/json-mutation-format/

I don’t get your question. If you do a query, you know what you are looking for. And what to extract. It can have N fields.

The trick is to understand if you create nodes and connect them in the same query or if you connect existing nodes.
in the mutation

{
  "set":[
     {
      "name": "Alice",
      "friend": {
        "name": "Betty"
      }
    }
  ]
}

from the doc, Dgraph will create 2 entities (node) and entity with name Alice will have a predicate “friend” to an entity with name Betty (second entity). the “friend” predicate is your ‘connection’.

You can also tell dgraph that an existing node has relations with other existing nodes using the sample provided by @MichelDiz with “uid”. and you can put has many relations as you want in the same mutation.

Here is a mutation that I am trying to do.

{
    "set": [
        {
            "Person.job": {
                "uid": "0x850ea4f"
            },
            "Person.is_adult": false,
            "Person.type": {
                "uid": "0x850f366"
            },
            "Person.name": "Test Name",
            "dgraph.type": "Person"
        }
    ]
}

The Person.job (0x850ea4f) and Person.type (0x850f366) already exist. The problem is that the connections for those two are missing. What am I doing wrong?

The parent one, is a NEW person? If not so, the parent should have uid too.

{
    "set": [
        {
            "uid": "0x1"
            "Person.job": {
                "uid": "0x850ea4f"
            },
            "Person.is_adult": false,
            "Person.type": {
                "uid": "0x850f366"
            },
            "Person.name": "Test Name",
            "dgraph.type": "Person"
        }
    ]
}

If you don’t provide the UID on all levels. Dgraph will create new nodes.

Run this query

{
   q(func: has(Person.job)) {
    uid
     Person.job {
      uid
    }
    Person.is_adult
    Person.type {
      uid
    }
    Person.name
    dgraph.type
    }
}

You probably have a lot of duplicates right now.

What uid do you mean? This is supposed to be generated by dgraph since my intention here is to add new data.

Okay, So there’s no problem at all in your mutation.

Share your query and schema.

There is since the 0x850ea4f and 0x850f366 doesn’t have this Person in their persons value. The connection was never made.

So, this is a social network? your model.

One more question, why you have a so big uid value? 0x850ea4f is = 139 million.

This is just an example. Let me try to give you another one.

Let’s say we have this schema.

type Brand {
  id: ID!
  name: String! @id @search
  websites: [Website!] @hasInverse(field: brand)
}

type Website {
  id: ID!
  brand: Brand! @hasInverse(field: websites)
  name: String! @id @search
  domain: String @search
}

A Brand with `uid: “0x12345” and name: “Test Brand” exist, so to add a new website I do

{
    "set": [
        {
            "Website.brand": {
                "uid": "0x12345"
            },
            "Website.name": "Test Name",
            "Website.domain": "domain.com"
            "dgraph.type": "Website"
        }
    ]
}

After this mutation I can query the Website and the brand is correct there.

The problem is that when I query the Brand, it doesn’t contain the Website I created.

Okay. I got it.

You are trying to mix GraphQL and DQL procedures. hasInverse is a ~feature that you can automatically link both nodes/entities during a mutation. But in DQL this doesn’t work. You need to follow the standard logic used in GraphQL to get this to work.

I have not implemented this function. I can only speak theoretically about how it works. I strongly believe that you need to write all relations on all nodes.

e.g.

{
    "set": [
        {
            "uid": "_:Newbrand",
            "Website.brand": {
                "uid": "0x12345",
                   "Brand.websites": {
                   "uid": "_:Newbrand"
                     }
            },
            "Website.name": "Test Name",
            "Website.domain": "domain.com"
            "dgraph.type": "Website"
        }
    ]
}