Help: Indexing array elements

Hello FaunaDB community!

I’m experiencing an issue with creating an index on an array field within my documents. I have a collection called photos, where each document has a tags array, and each object in this array has a tag field. I want to create an index that allows me to search for documents based on the values in this tag field.

Here’s the structure of a typical document in my photos collection:

{
  "name": "Example Photo",
  "tags": [
    {
      "tag": "sushi",
      "user": "https://www.flickr.com/photos/example/",
      "date_create": "2004-08-28"
    },
    // other tags...
  ]
  // other fields...
}

I tried creating an index like this (and various permutations on the field names and dot notation):

photos.definition.update({
  indexes: {
    photosByTag: {
      terms: [{ field: "tags.tag", mva: true}],
      values: [{ field: "data.id"}],
    }
  }
})

However, when I use this index, it returns an empty data array, even though I have documents that match the query criteria.

According to the docs,

When an Array is indexed, an index entry is created for each of its elements.
A null value is indexed only when part of an Array. (link)

I’ve also confirmed that the documents are structured as expected and that the index has had sufficient time to build (by checking photos.definition). Can anyone suggest what might be going wrong or if there’s a different approach I should take for indexing elements within an array?

Any insights or suggestions would be greatly appreciated!

Thank you, Jennie

Hi @jennierf and welcome! :wave:

Index terms and values can work on an array field, but you cannot specify additional fields for objects within an array. If you are using an array as a term or value, the path has to end at the array. Any additional elements in the path will cause the index to expect an object with another field.

To work around this, you should store an array with just the tags you want to be indexed.

{
  "name": "Example Photo",
  "tags": [
    {
      "tag": "sushi",
      "user": "https://www.flickr.com/photos/example/",
      "date_create": "2004-08-28"
    },
    // other tags...
  ],
  "tags_array": ["sushi", /* ... */],
  // other fields...
}
// update with FQL
photos.definition.update({
  indexes: {
    photosByTag: {
      terms: [{ field: "tags_array", mva: true}],
      values: [{ field: "id"}], // you don't need to specify `data`
    }
  }
})

Compared to FQL v4

If you are familiar with FQL v4, you will note that this is different. In v4, arrays were always used as multi-value attributes (MVAs). With v10 we added the ability to specify whether a term or value should be an MVA or not. That comes with some tradeoffs, because going back and forth between objects and arrays there might be several levels. We’ve kept the index definition as a simple flag, rather than require a complex annotated path.

Calculated fields

We are working on introducing “calculated fields” in the near future. This would make using your index much easier.

Right now, you will need to make sure that every time the tag array is updated, you need to update the tags_array field. A good way to do this is to only perform CRUD operations through UDFs that ensure that the everything is written correctly.

Once calculated fields are launched, you can define fields that will be written to your documents every time they are updated. removing the extra work to keep the field in sync yourself.