Get the collection name from a document reference

What I want to do:
A UDF provides a standardised function that works across most collections in a given database. It accesses an index of a collection, and performs useful actions with it. Pass in any document reference, and have this function determine what index it should access to perform the actions. Rather than have a long list of collections and indexes, we dynamically build the index name, given the collection name extracted from the incoming document reference.

How I intend to dynamically build the name of index name:
Get the string value of a collection name from a document reference so that we can use it to build the new name of an index.
Example: From a document reference of a user document, we extract the name ‘users’, we then add a suffix to this like ‘_document_locks’ to produce a new name ‘users_document_locks’ that is then used as an index name to perform some action.

Something like this (which works):

ref : Ref(Collection("users"), 123)
collection_ref : Select(['collection'], Var('ref'))  	// Gives Collection("users")
collection : Get(Var('collection_ref'))					// Load collection header
collection_name : Select('name', Var('collection'))		// Extract name from the header array
index_name : Concat([Var('collection_name'), '_document_locks'])

I really feel this method is not performant though. It is reading the header of a collection - which feels completely unnecessary, even if it does work.

How about if I just extract the name from Collection("users") like this:

ref : Ref(Collection("users"), 123)
collection_ref : Select(['collection'], Var('ref'))  	// Gives Collection("users")
collection_string : SubString(
	Var('collection_ref'), 
	13, 
	Subtract(Length(Var('collection_ref')), 15)
)

Produces an error:

"code": "invalid argument",
"description": "String expected, Collection Ref provided."

OK, so let’s make it a string:

string_representation : ToString(Var('collection_ref'))

Produces an error:

"code": "invalid argument",
"description": "Cannot cast Collection Ref to String."

It also cannot be converted to an object or array either using ToObject or ToArray.

So the issue is that we are dealing with a reference - which makes sense because the string Collection("users") isn’t a string - it’s a command to load a reference to the users collection. It is a token (in terms of code) that represents an actual reference to a collection. But the string representation of this is Collection("users") as you can see in the output of collection_ref in the below example code:

Let(
  {
    ref : Ref(Collection("users"), 123),
    collection_ref : Select(['collection'], Var('ref')),
    id : Select(['id'], Var('ref')),
    collection_header : Get(Var('collection_ref')),
    collection_name : Select('name', Var('collection_header'))
  },
  {
    ref : Var('ref'),
    collection_ref : Var('collection_ref'),
    collection_header : Var('collection_header'),
    collection_name : Var('collection_name'),
    index_name : Concat([Var('collection_name'), '_document_locks'])
  }
)

Produces:

{
  ref: Ref(Collection("users"), "123"),
  collection_ref: Collection("users"),
  collection_header: {
    ref: Collection("users"),
    ts: 1628173873083000,
    history_days: 30,
    name: "users"
  },
  collection_name: "users",
  index_name: "users_document_locks"
}

My question then is : is there a way of extracting the name from a document reference that is faster and simpler than what I have done above?

Does it make sense to be concerned with using Get(Var('collection_ref')) which in my imagination has to go off and access the DB creating an unnecessary round trip (yes, I know the function executes within the Fauna space itself, but still I would imagine it’s actually accessing various servers for various things at various times).
I do not know how the system is architected, am I worrying about nothing?
What happens if I have a list of documents, like 5000 of them, and they are mixed collections, so my UDF gets called for each and every one of them instead of only once at the beginning (because we cannot presume that they are all from the same collection)?

Any thoughts anyone? Thank you kindly!

You can get the collection id from a reference like this:

> Select(["collection", "id"], Ref(Collection("Letters"), "101"))
'Letters'
1 Like

FYI: I updated the recipe for document references in the Cookbook to show this use case: Document reference - Fauna Documentation

2 Likes

@ewan you are a star! Thank you for taking the time to read through my post, and giving a suggestion. That’s perfect!
Interesting that it is called ‘id’ and not ‘name’.

1 Like

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