How to return the single value of an index

Hey Fauna team!

Just wondering what the best way is to get the value from an index that returns a single value and not a ref. For example, let’s say I have a collection of documents that have the following:

{
   id: string
   title: string
}

and I have an index set up to ensure they’re unique:

CreateIndex({
   name: 'book-by-id',
   source: Collection('books'),
   unique: true,
   serialized: true,
   terms: [{ field: ['data', 'id'] }]
})

And then another index which returns only the title based on ID:

CreateIndex({
   name: 'book-title-by-id',
   source: Collection('books'),
   unique: false,
   serialized: true,
   terms: [{ field: ['data', 'id'] }],
   values: [{ field: ['data', 'title'] }]
})

If I use Get(Match(Index('book-title-by-id'), 'some-id')) it will get the document, not really what I need. Currently we’ve been doing something like:

Select(0, Paginate(Match(Index('book-title-by-id'), 'some-id')))

Which successfully returns only the title. But this index will always return only one record because unique: true is set on the book-by-id index. Is there a way to just get the first value returned, or is this best way to do it?

I couldn’t find any other questions similar, so happy to be pointed in the right direction if this has been asked before.

Thanks heaps!

As you have noted, if you don’t want the full document, use Paginate instead of Get.

Your Select expression does not involve your book-by-index index, so the fact that it has unique: true set makes no difference. The book-title-by-id index does not require uniqueness, so multiple values could be returned.

That said, Select does get just the first value returned.

When you use Paginate, it returns a Page of results, which looks like an object containing a data field that contains an array (plus before and after cursor fields if there are previous/next pages in the result set), but it otherwise behaves as an array. That’s why your Select expression does what you expect.

Each entry in the result set resembles the values definition in the involved index. If there is a single field defined in values, the result set contains just that field’s value. If your values defines multiple fields, you get an array.

You can use Select to extract specific array entries, e.g. Select([0, 1], Paginate(...)), which would select the first entry in the page (0), and then the second item in that entry (1).

I hope that helps!

Thanks Ewan, that all makes sense, that confirms my understanding. I guess I was just hoping for a simplified version of this given that in this scenario Paginate(Match(Index('book-title-by-id'), 'some-id')) would always return one result. Maybe something like a Head or something like that, but no worries, that’s fine. I guess I could always write a UDF to manage this right? On the other hand, it’s not that hard to just write it as I have done.

You are not the first to ask for this. There might be a simpler way later this year; discussions are underway for new FQL functions which might include First(n) and Last(n).

In the meantime, you could certainly create a UDF to handle it, especially if you need that capability in more than a few queries.

1 Like

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