faunadb

Faunadb create index on child item field


I'm trying to get an index on a field of a child item in my document. The data is this:

[
   {
      "ref": Ref(Collection("ColA"), "111111111111111111"),
      "ts":1659241462840000,
      "data":{
         "name":"Test a",
         "members":[
            {
               "userId":"1",
               "roles":[
                  "admin"
               ]
            }
         ]
      }
   },
   {
      "ref": Ref(Collection("ColA"), "111111111111111112"),
      "ts":1659241462840000,
      "data":{
         "name":"Test b",
         "members":[
            {
               "userId":"1",
               "roles":[
                  "admin"
               ]
            },
            {
               "userId":"2",
               "roles":[
                  "read-only"
               ]
            }
         ]
      }
   },
   {
      "ref": Ref(Collection("ColA"), "111111111111111113"),
      "ts":1659241462840000,
      "data":{
         "name":"Test c",
         "members":[
            {
               "userId":"2",
               "roles":[
                  "admin"
               ]
            }
         ]
      }
   }
]

Trying to using data.members.userId as term in the index. This only gives back one result when I use the index with the filter value '1'

Then I tried to create the index as following:

CreateIndex({
  name: 'spaces_member_ids',
  source: {
    collection: Collection("ColA"),
    fields: {
      members: Query(
        Lambda(
          "ColA",
          Select(["data", "members", "userId"], Var("ColA"), '') 
        )
      ),
    },
  },
  terms: [
    { binding: "members" },
  ],
  values: [
    { field: "data.name" },
    { field: "ref" },
  ]
})

But that gives no results when I use the index with the filter value '1' Both times I expect to get two items back (Test a and Test b).

Anyone knows how to create an index that gived back all the data of ColA filtered on field 'userId' in the 'members' array?


Solution

  • The problem is that there is no userId field as a direct descendant of the members array.

    For background, Fauna index entries can only contain scalar values. Objects are not indexed at all. For arrays, one index entry is created per scalar value in the array. If you attempt to index multiple array fields, the number of index entries produced is the Cartesian product of the items in all indexed arrays.

    If you create your index like so:

    CreateIndex({
      name: 'spaces_member_ids',
      source: Collection("ColA"),
      terms: [
        { field: ["data", "members", 0, "userId"] },
      ],
      values: [
        { field: ["data", "name"] },
        { field: "ref" },
      ]
    })
    

    Then you'll be able to search for userId values that appear in the first item in the members array.

    If you need to create index entries for all userId values from each ColA document, then your binding approach is close, but it needs to provide an array.

    CreateIndex({
      name: "spaces_member_ids",
      source: {
        collection: Collection("ColA"),
        fields: {
          members: Query(
            Lambda(
              "ColA",
              Map(
                Select(["data", "members"], Var("ColA"), []),
                Lambda(
                  "member",
                  Select(["userId"], Var("member"), "")
                )
              )
            )
          ),
        },
      },
      terms: [
        { binding: "members" },
      ],
      values: [
        { field: ["data", "name"] },
        { field: "ref" },
      ]
    })
    

    The notable changes that I made are: