Getting only index values of first match

I have an index defined like this:

{
  name: "foo_by_term_and_another_term",
  source: Collection("foo_bar"),
  terms: [{ field: ["data", "term"] }, { field: ["data", "anotherTerm"] }],
  values: [{ field: ["data", "fooID"] }],
}

From documentation, it is possible to get the first matching document:

If Match only returns a single document, or only the first document is needed, Get may be used to retrieve the document.

For example Get(Match(Index("foo_by_term_and_another_term"), ["term", "anotherTerm"])). This will return the first matched document.

However my index definition only has fooID in its values. Is there a simple way to only get fooID instead of the whole document. I’m currently doing:

Select(
  ["data", "fooID"]
  Get(
    Match(
      Index("foo_by_term_and_another_term"),
      ["term", "anotherTerm"]
    )
  )
)

You seem to have found a documentation bug.

Get(Match(...)) only works when the results are comprised solely of document references. We recently updated the Get :: Fauna Documentation coverage to indicate that it works only with a set of references, but we missed updating the Match :: Fauna Documentation coverage too. I’ve filed DOCS-2061 to get that fixed.

Since you only want to return fooID, you can use Paginate to materialize the result set from the Match call:

Paginate(
  Match(
    Index("foo_by_term_and_another_term"),
    ["term", "anotherTerm"]
  )
)

If you just want the first result, and to be defensive against the case where there are no results, Select with a default value helps:

Select(
  ["data", 0],
  Paginate(
    Match(
      Index("foo_by_term_and_another_term"),
      ["term", "anotherTerm"]
    )
  ),
  null
)
2 Likes

What is supposed to happen when Get(Match(...)) is run against an index that returns values and not documents? Is it supposed to throw an error? If so, I’m not observing this behaviour in the latest version of the Docker Fauna image. Get(Match(...)) returns the first document hence why I can do the following:

What is supposed to happen when Get(Match(...)) is run against an index that returns values and not documents?

You should get an error:

> Get("Test")
Error: invalid argument
{
  errors: [
    {
      position: [
        'get'
      ],
      code: 'invalid argument',
      description: 'Ref or Set expected, String provided.'
    }
  ]
}
> Get(1234)
Error: invalid argument
{
  errors: [
    {
      position: [
        'get'
      ],
      code: 'invalid argument',
      description: 'Ref or Set expected, Integer provided.'
    }
  ]
}

When given a reference, Get fetches that document from the database:

> Get(Ref(Collection("users"), "1"))
{
  ref: Ref(Collection("users"), "1"),
  ts: 1650301304550000,
  data: { name: 'Alice Crypto', email: 'alice@site.example.com' }
}

If you provide Get with a set reference, and the set contains references, Get “helpfully” retrieves the first reference in the set.

> Get(Match(Index("foo_by_term_and_another_term"), ["Alice Crypto", "alice@site.example.com"]))
{
  ref: Ref(Collection("users"), "1"),
  ts: 1650301304550000,
  data: { name: 'Alice Crypto', email: 'alice@site.example.com' }
}

(I don’t have your documents, I so made an index with the same name against the “users” collection used to provide examples in the documentation.)

If the set is empty, Get returns an error:

> Get(Match(Index("foo_by_term_and_another_term"), ["data", "data"]))
Error: instance not found
{
  errors: [
    {
      position: [],
      code: 'instance not found',
      description: 'Set not found.'
    }
  ]
}

If you are getting a document from your sample query, then your index is returning at least one document reference, which Get can use to fetch the document itself.

Here’s a quick reproduction and also clarification on what I expected compared to what actually happened:

Setup

CreateCollection({ name: "foo_bar" })

CreateIndex({
  name: "foo_by_term_and_another_term",
  unique: false,
  serialized: true,
  source: "foo_bar",
  terms: [{ field: ["data", "term"] }, { field: ["data", "anotherTerm"] }],
  values: [{ field: ["data", "fooID"] }]
})

Create(
  Collection("foo_bar"),
  {
    "data": {
      "term": "term",
      "anotherTerm": "anotherTerm",
      "fooID": "foo-123"
    }
  }
)

Query

Get(Match(Index("foo_by_term_and_another_term"), ["term", "anotherTerm"]))

Expectations

Given the index specified values to be fooID, I’d expect Match to return only those values. This does seem to be the case when doing Paginate(Match(Index("foo_by_term_and_another_term"), ["term", "anotherTerm"])).

For Get, the documentation reads:

When the result of calling Match is a set of one or more References, you can call Get on the result to retrieve the first document.

However in this case, Match shouldn’t return a set of one or more references because values has been specified on the index. Is this expectation correct? As a result, calling Get shouldn’t have the behaviour elaborated in the above quote?

Actual

Running Get(Match(Index("foo_by_term_and_another_term"), ["term", "anotherTerm"])) returned the first document, as if values had not been specified on the index. This lets me do:

Select(
  ["data", "fooID"]
  Get(
    Match(
      Index("foo_by_term_and_another_term"),
      ["term", "anotherTerm"]
    )
  )
)

Notes

Just want to make clear, that I don’t have a strong opinion on what the actual behaviour should be, and that I’m just trying to make sense of what I’ve read from documentation.

After checking with engineering, the original description of Get's behavior was more accurate than what it was changed to.

When Get is provided with a set reference from a Match expression, it has access to the entire set of index entries. Each index entry includes the covered document’s reference, even if the values definition does not specify the ref field.

So, Get(Match(Index("foo_by_term_and_another_term"), ["term", "anotherTerm"])) can always fetch the first document.

Apologies for the confusion in this conversation. We’re updating the documentation to make this clear.

1 Like

Just a quick followup: the paragraphs relevant to this discussion have been updated:

1 Like

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