@id and @hasinverse on specific type

Hello, I’m trying to build an app with golang and dgraph, and I’m unable to make a @id working with @hasInverse

I’m using the following Schema :

type Account {
    email: String! @id @search(by: [hash, regexp])
    sessions: [Session] @hasInverse(field: account)
}

type Session {
    id: ID!
    account: Account! @hasInverse(field: sessions)
    mail_to: String! @search(by: [hash, regexp])
    mail_from: String! @search(by: [hash, regexp])
    mail_text: String!
    mail_html: String!
    mail_subject: String! @search(by: [hash, regexp])
    mail_original: String!
}

An account is identified by it’s email (so there should be only one object with the same mail address … In my case, I can insert several time the SAME mail address and have a different object …)
A session belong to a user and should be reversed in the account’s sessions array

My golang mapping for this, is the following:

type Account struct {
	Email string `json:"Account.email,omitempty"`
	Sessions []Session `json:"Account.sessions,omitempty"`
	DType    []string  `json:"dgraph.type,omitempty"`
}

type Session struct {
	ID           string    `json:"Account.id,omitempty"`
	MailTo       string    `json:"Session.mail_to,omitempty"`
	MailFrom     string    `json:"Session.mail_from,omitempty"`
	MailText     string    `json:"Session.mail_text,omitempty"`
	MailHTML     string    `json:"Session.mail_html,omitempty"`
	MailSubject  string    `json:"Session.mail_subject,omitempty"`
	MailOriginal string    `json:"Session.mail_original,omitempty"`
	CreatedAt    time.Time `json:"Session.created_at,omitempty"`
	Account      Account   `json:"Session.account,omitempty"`
	DType        []string  `json:"dgraph.type,omitempty"`
}

If I use the name without the Session or the Account, it create other predicates … so is this the correct way to use dedicated types in golang ?

My code to insert my object is the following :

	pb, err := json.Marshal(data.Session{
		CreatedAt: time.Now(),
		MailTo:    "test2@test.com",
		MailFrom:  "mf@rlol2.com",
		MailText:  "text222",
		DType:     []string{"Session"},
		Account:   data.Account{Email: "test2test@test.com", DType: []string{"Account"}},
	})
	mu := &api.Mutation{SetJson:   pb,CommitNow: true}
	if res, err := dg.NewTxn().Mutate(ctx, mu); err != nil {...}

My questions are :

  • In theory, if I insert an account, the email is the only id (when i’m querying dgraph, I always end up with uid that are generated … is that normal? so in my case if I create several time an account with the SAME email I end up with several time the SAME email in dgraph … with the @id there sshould be only one no ?)

  • If I create a session with an account linked to it, when I query that account, I’m suppose to get an array of session ?
    in my case when I request account, I don’t get the array of sessions :

{
  node(func: type(Account)) @recurse(depth:3){
    uid
    expand(_all_)
  }
}

return :

"data": {
    "node": [
      {
        "uid": "0x27",
        "Account.email": "test2test@test.com"
      }
    ]
  },

And when I query Session :

{
  node(func: type(Session)) @recurse(depth:3){
    expand(_all_)
  }
}

it returns :

"data": {
    "node": [
      {
        "Session.account": {
          "Account.email": "test2test@test.com"
        },
        "Session.mail_to": "test2@test.fr",
        "Session.mail_from": "mf@rlol2.fr",
        "Session.mail_text": "text222"
      }
    ]
  }

So I have my account that is stored in Session but isn’t returned by Account’s sessions array… what am I doing wrong ?

Thanks

Hi there @lzr , welcome to the Dgraph community!

I noticed something strange about your schema: you have TWO @hasInverses .

Based on what you want to do, the following schema is more than enough:

type Account {
    email: String! @id @search(by: [hash, regexp])
    sessions: [Session] @hasInverse(field: account)
}

type Session {
    id: ID!
    account: Account! # THIS WAS REMOVED.
    mail_to: String! @search(by: [hash, regexp])
    mail_from: String! @search(by: [hash, regexp])
    mail_text: String!
    mail_html: String!
    mail_subject: String! @search(by: [hash, regexp])
    mail_original: String!
}

Now on to your questions:

It’s normal.

That’s funny. That shouldn’t happen. I will try to reproduce based on your queries/code

I noticed you used expand(_all_). That function only expands terminal nodes. To get the sessions, you need to do this:

{
  node(func: type(Account)) @recurse(depth:3){
    uid
    expand(_all_)
    Account.sessions {}
  }
}

Hello, thanks for your answer, when I use your request :

I get the following error :

"message": ": Repeated subgraph: [Account.sessions] while using expand()",