Using an upsert block to increment an ID

I’m trying to use an upsert block to increment an ID value on creation so I can have my own internal node IDs that are only unique to other nodes of the same type. I’m basing this on questions like this one which includes the same solution I came up with but it’s not working for me: How to use Dgraph to automatically increase ID?

I have the following manually-created users with my own xid field:

Query:

{
  var(func: type(User), first:-1) {
    lastid as xid
    newid as math(lastid + 1)
    }
  q(func: type(User)) {
    xid
    FirstName
    val(newid)
  }
}

Result:

"q": [
      {
        "xid": 1,
        "FirstName": "Chris"
      },
      {
        "xid": 2,
        "FirstName": "Phil",
        "val(newid)": 3
      }
    ]
  }

I want the value of “newid” which in this case is “3” to be able to be used in the mutation block of an upsert block like this:

upsert {
  query {
    q(func: type(User), first:-1) {
    lastid as xid
    newid as math(lastid + 1)
    }}

  mutation {
    set {
	_:user <dgraph.type> "User" .
      _:user <FirstName> "Matt" .
      _:user <LastName> "None" .
      _:user <Email> "matt@example.com" .
      _:user <Password> "password" .
      _:user <xid> val(newid) .
    }
  }
}

The above upsert mutation works but the xid is never set which I assume means it’s empty when executing the mutation block. How do I get my newid value into the mutation block where I need it?

The first query which returns my users seems to suggest the value only exists in the context of a specific node since the newid value isn’t shown on the “Chris” node which is why it seems to be empty during my mutation.

1 Like

I think relying on sorting of UIDs to get the latest inserted user would be a bad approach. We assign UIDs in batches and a later inserted user could potentially have lower UID. A better approach may be to keep a separate predicate and store the latest ingested XID there, like a counter and use that instead. This can have some negative impact on performance, though, happy to explain more if you have any question with the approach.

I’m not relying on the UIDs. That’s just an example from the linked post. I’m actually using orderdesc: xid, first:1 to get the last saved xid. My problem is the variable not being recognized in the mutation block which wouldn’t be solved by changing how it’s stored.

Will you share the actual query? In the above query, I see you are using first:-1 which I thought could be problametic.

upsert {
  query {
    var(func: type(User), orderdesc: xid, first:1) {
    lastid as xid
    newid as math(lastid + 1)
    }}

  mutation {
    set {
      _:user <dgraph.type> "User" .
      _:user <FirstName> "Matt" .
      _:user <LastName> "None" .
      _:user <Email> "matt@example.com" .
      _:user <Password> "password" .
      _:user <xid> val(newid) .
    }
  }
}

This seems like a bug similar to already raised on GitHub here Bug with multi-level Upsert Block · Issue #4692 · dgraph-io/dgraph · GitHub. I am looking into this issue. The problem is the line _:user <xid> val(newid) .. I will post more updates soon. Thanks

This is a similar bug, and we will fix it as soon as we can. I have posted an example on the GitHub issue Bug with multi-level Upsert Block · Issue #4692 · dgraph-io/dgraph · GitHub.

@MichelDiz pointed out that there is a separate GitHub issue that tracks this issue It is not possible to create a new node from another using Upsert Block · Issue #4712 · dgraph-io/dgraph · GitHub.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.