Ref to a node without an ID

Hi there. May I know if there is any way to add a Ref to a Node (Type) without an ID field?

That is, lets say I want to ref to a node based on the value of one of its properties, how would I do this?

Also, is it possible to use @hasinverse in this case? Thanks.

By using @id.

e.g.

type Tweet {
  id: ID!
  tagged: [HashTags!]
}

type HashTags {
  name: String! @id // Only by having that property as an id, makes it possible.
  tweet: Tweet! @hasInverse(field: tagged) // hasInverse is possible as well.
}
1 Like

Awesome. Just one follow up question here if you don’t mind.

If I have a case where

type Tweet {
  id: ID!
  metadata: [MetadataObject!]
}

type MetadataObject {
  key: String! //Let's say that this metadata is unique per tweet but not globally
  tweet: Tweet! @hasInverse(field: tagged) // hasInverse is possible as well.
}

May I know how it would work in this case?

type Entity {

    entityID: ID!

    attributes: [Attribute] @hasInverse(field: belongsTo)

}

type Attribute {

    key: String! @search(by: [hash])

    value: String!

    attributeType: AttributeTypeEnum!

    belongsTo: Entity!

}

type View {

    viewID: ID!

    attributeList: [Attribute]

}

In this case, I want to be able to refer an already created attribute to the view in the attribute list.

I was able to do this with ID as you mentioned but without ID, can I refer to it with the attribute key

The reason for not using id in attribute is because attribute key is unique per entity but not globally. I guess @id will make it globally unique

It won’t it will actually add a new node with those properties instead of creating the ref. Linking ref nodes only work with xid’s (using @id) or guids (using ID scalar) . I’ve been down this path already. Sorry. Maybe a custom Mutation will help, more work, yes, but maybe worth it??

2 Likes

As @amaster507 said, not possible.

Yup.


P.S.

attributes: [Attribute] @hasInverse(field: belongsTo) is wrong.

hasInverse needs to be on

belongsTo: Entity! @hasInverse(field: attributes)

1 Like

@amaster507 @abhijit-kar Thanks for your help. Maybe I have to add an @id field to the attribute entity then and refer to that in addition to the key and value I have.

PS: The schema was just a rough one to give you an idea removing unnecessary stuff. Sorry for the mistakes :sweat_smile:

I’m confused on why hasInverse needs to be on belongsTo, please explain :grinning:

Because one way connection is implicit, but to make it two way you have to add hasInverse to the child type.

type Entity {
    entityID: ID!
    attributes: [Attribute] // Here linking is implicit, no need to add hasInverse
}

type Attribute {
    key: String! @search(by: [hash])
    value: String!
    attributeType: AttributeTypeEnum!
    belongsTo: Entity! @hasInverse(field: attributes) // Here it has to be added explicit
}

So I ask the question, which is the child and which is the parent? A child can have two parents yes? A parent can have more than one child (We don’t live in China, lol) Yes? You have to break the thinking of parent -> child and look at it Node <-> Node

unless you want to catch make it a two way edge.

2 Likes

I was wrong.

I remember you mention this previously.

Doesn’t matter on which side @hasInverse is used, it just works.

My bad @gorillastanley & @tvvignesh. :sweat_smile:

1 Like

I am curious as to why you don’t want to have the ID field?

@abhimanyusinghgaur Actually I wanted to have a sort of composite key where both entity id and attribute key together becomes the ID but since composite key is not supported by Dgraph, that’s something which I cannot do.

If I use a separate ID field, then that is going to just act as an identifier to the respective attribute without any other utility whatsoever since I would be referring to every attribute only by its key everywhere and not the ID. So, I thought of not using ID (just to make it possible to ref).

Rather if I had the option to get IDs out of both entityID as well as attribute key (composite key), then that makes a lot of sense. Hope this clarifies.

  1. Just to support your use-case, I thought of this:
    Have an @id field in both Entity and Attribute. If you are setting the @id field in Entity to some value lets say "entity1", then set the @id field in Attribute to "entity1_attribute1". I think that way you will get the behavior you are looking for. And, you can have another field in Attribute, let’s say it is called name, have @search directive on it, and set its value to attribute1. So, the attribute1 value for name may be repeated across multiple nodes, but the @id field value will be unique for each node. So, while referring you will be able to refer to each attribute node uniquely, but at the same time, you will also be able to find all the Attributes which are attribute1.

  2. Also, wanted to clarify if by using a composite key you are looking for the capability to be able to search Attributes having a particular key within an Entity, then you can use custom DQL for that use case. You could modify your schema like:

    type Entity {
        entityID: ID!
        attributes: [Attribute]
    }
    
    type Attribute {
        key: String! @search(by: [hash])
        value: String!
        attributeType: AttributeTypeEnum!
        belongsTo: Entity! @hasInverse(field: attributes)
    }
    
    type Query {
      getAttributeInEntity(entityID: ID!, key: String!): Attribute @custom(dql: """
      query q($entityID: string, $key: string){
        var(func: uid($entityID)) {
          keyAttr as Entity.attributes @filter(eq(Attribute.key, $key))
        }
        getAttributeInEntity(func: uid(keyAttr)) {
          key: Attribute.key
          value: Attribute.value
          attributeType: Attribute.attributeType
          belongsTo: Attribute.belongsTo {
            entityID: uid
          }
        }
      }
      """)
    }
    

    And then use getAttributeInEntity query to find out the attribute with a particular key in a particular entity. But this way, one would still be able to add duplicate attributes in an entity, and then the above query may error out, because of a list of attributes being returned instead of a single attribute. So, this doesn’t satisfy the full needs of a composite key but it depends if you want to use it.

  3. Finally, having the capability to specify node uniqueness for an edge in the graph seems like a good new feature. So, something like @unique directive can be supported later:

    type Entity {
        entityID: ID!
        attributes: [Attribute] @hasInverse(field: attributes) @unique(field: key)
    }
    
    type Attribute {
        key: String! @search(by: [hash])
        value: String!
        attributeType: AttributeTypeEnum!
        belongsTo: Entity!
    }
    

Thanks for mentioning the composite key use-case.

3 Likes

@abhimanyusinghgaur: Wow! That was an elaborate reply. Thanks for thinking this through in such depth.

I thought about case 1 as you mentioned and that looks like the simplest one to get it implemented, but then did not move forward with that since I was not sure if it is okay to do that (felt kind of hacky, not sure though)

Case 2 seems interesting (using DQL within GQL) to enable search. Will this just narrow down the search within the attributes of that entity without checking other entities? That can speed up a lot of time taken for search.

And finally case 3 definitely looks way cleaner. Looking forward to something like that so that we can have the uniqueness constrained within the children alone rather than having it globally.

Btw, while unrelated to this topic, I really have to commend the effort of the Dgraph team in the way all of you stick around to help the community and I really appreciate the effort you are putting in to make Dgraph great.

I even happened to see this: Devotee badge on Discuss Dgraph and that takes some real devotion. @MichelDiz visiting 1 year continuously.

Not just this, I even see people from the community like @amaster507 and @abhijit-kar hanging around to help which is really great to see.

I am really new to Dgraph (have been using it for past 3 days I guess and I have already completed work with the DB schema and all queries related to it which really shows the speed at which we can get things done and that’s great)

Thanks again. Have never run Dgraph in production, planning to do it soon. Fingers crossed :sweat_smile:

CC: @mrjn

5 Likes

Yes!

Thanks for praising the efforts of the team and for getting us a new feature to think about :smile:

1 Like