Given the iid of something in the graph, how to retrieve it?

I recently asked, in the thread here:

https://forum.typedb.com/t/how-to-get-the-unique-identifier-of-a-thing-in-the-graph/554/8

“How to get the unique identifier of a thing in the graph?” Now I have the inverse question: Given the iid of something in the graph, how can you query to retrieve that thing?

I understand that (although I don’t understand why) iid is not a normal attribute, and cannot be queried like the others. But get and fetch seem like the only methods remotely suited to the task. Both of the following queries (using the Python driver) elicit a no viable alternative error at the word iid. I imagine that means "No (ordinary) attribute called iid belongs to the class person.

data_get ( db = DB_NAME, query = "match $p isa person, has iid '0x826e80018000000000000000'; get $p;" )

data_fetch ( db = DB_NAME, query = "match $p isa person, has iid '0x826e80018000000000000000'; fetch $p: iid;" )

I’ve put the definitions of data_get and data_fetch at the end of this post. Aside from the list comprehension trick, they’re straight from the TypeDB QuickStart code.

I’ve reread the documentation on fetch, get, and concepts. None of the patterns seem relevant, nor do any of the statements (is gave me hope, but no dice). And yet there must be a way to do this, right?

If there isn’t, of course, I can just generate my own attribute, parallel to and unique like iid, but queriable in the ordinary way. But it would be embarrassingly inelegant.

def data_fetch (
    db : str,
    query : str
) -> ( Dict # Recursive JSON, whose type can't be specified
       # completely -- e.g. its depth depends on the query.
      ):
  with TypeDB.core_driver (
      SERVER_ADDR ) as driver:
    with driver.session ( db,
                          SessionType . DATA ) as session:
      with session.transaction (
          TransactionType.READ ) as tx:
        return [ # The fetch object is an iterator
          # that becomes useless when the session ends.
          # This list comprehension
          # lets me smuggle the results outside the function.
          r for r in tx.query.fetch ( query ) ]

def data_get (
    db : str,
    query : str
) -> List [ # todo: Why are these `_ConceptMap`s, and how do
            # those differ from `ConceptMap`s (without "_")?
  _ConceptMap ]:
  with TypeDB.core_driver (
      SERVER_ADDR ) as driver:
    with driver.session ( db,
                          SessionType . DATA ) as session:
      with session.transaction (
          TransactionType.READ ) as tx:
        return [ # The get object is an iterator
          # that becomes useless when the session ends.
          # This list comprehension
          # lets me smuggle the results outside the function.
          r for r in tx.query.get ( query ) ]

Hi, iid is a constraint forming keyword, similar to isa or has. This means that rather than treating it as a type label following has, as in your query above, you should instead use it in place of has:

match $p iid 0x826e80018000000000000000; get $p;

A few other pointers:

  • You should not use isa and iid constraints on the same variable, as the iid constraint already contains the typing information.
  • IIDs should not be enclosed in quotes.
  • You can treat an iid constraint like any other constraint, and combine it with other constraints to form a pattern in the match clause, which can be followed by either a get or a fetch clause as needed.

You should be aware that the iid keyword and the ability to retrieve IIDs are currently deprecated. Whether internal identifiers will be accessible in TypeDB 3.0 is still an open question, and it might take a very different form to the 2.x implementation.

Correction: apparently it is possible to use isa and iid together to check if a given data instance is of a given type, but I’m not sure how this will behave.

it is possible to use isa and iid together to check if a given data instance is of a given type, but I’m not sure how this will behave.

As always, It should behave as a conjunction of the iid constraint and the isa constraint. Which means the conjunction will fail if the instance isn’t of the specified type (or a subtype)

1 Like

Aha! Thanks.

Is iid absent from the documentation (TypeDB | Docs > TypeQL > Keywords) because you plan to remove it?

Am I the only user you’re aware of who wants to be able to hold onto unique identifiers? I’m writing a note-taking app in TypeDB, where certain regions on the screen correpond to elements of the graph. Based on where the cursor is I want to be able to talk about the corresponding graph element with TypeDB – change its text, fetch objects in a certain kind of relationship with it, etc. If I lose the ability to access the iid I’ll definitely have to create a parallel one.

I’m not complaining – like I said earlier, making a redundant field so I can access it is easy enough. But it’s hard for me to imagine I’m the only person who finds access to IIDs useful.

IIDs are not currently static: they can be re-assigned as needed. This means that if you use an IID to identify a database object, the same IID will not necessarily refer to the same object next time you check. IIDs were not intended to be used as primary identifiers: they are literally “internal”, and should only be used in very specific ways. The same is true for equivalents in other databases, such as Oracle’s ROWID.

We decided to deprecate user-facing IIDs because they were being misused as primary identifiers, which could easily lead to problems when they are reassigned. This is also the reason that they aren’t currently documented. That said, IIDs will be static in TypeDB 3.0, and there are some thoughts about keeping them user-facing and making them easier to work with, as several users have indeed requested this.

For now, I would recommend implementing your own system of IDs.

Now I understand. Thanks, James!

1 Like