Index binding with ContainsField in Lambda function

Hi,

I am struggling with the correct syntax to check if a field exists in an entry for index binding.

My try:

CreateIndex({
  name: "test",
  source: [
    {
      collection: Collection("entries"),
      fields: {
        name: Query(
          Lambda('entry',
            Concat(
              [
                Select(['data',field_1'],Var('entry')),
                If(
                  ContainsField("field_3",Var('entry')), 
                  Select(['data','field_3'],Var('entry')), 
                  Select(['data','field_2'],Var('entry'))
                )
              ],
              " ")
            ),
          )
      }
    }
  ],
  terms: [],
  values: [
    { binding: "name" },
    ]
})

The problem seems Var(‘entry’) is not an “object” I can use with ContainsField.

I’ve used another approach to achieve the same. Nevertheless, it would be nice if using ContainsField, like above, is also possible.

New (working) approach:

CreateIndex({
  name: "test",
  source: [
    {
      collection: Collection("entries"),
      fields: {
        name: Query(
          Lambda('entry',
            Concat(
              [
                Select(['data',field_1'],Var('entry')),
                 Select(['data','field_3'],Var('entry'),Select(['data','field_2'],Var('entry')))
              ],
              " ")
            ),
          )
      }
    }
  ],
  terms: [],
  values: [
    { binding: "name" },
    ]
})

ContainsField can certainly be used in an index binding. However, it only checks the top-level field names; it does not return true for nested field names. You would need to change your ContainsField line to test the data object:

ContainsField("field_3", Select("data", Var('entry'))), 

Concat is a bit fussy: all of its concatenation items must be strings, or it throws a warning (which you can only see if you in a direct query, not when wrapping in Query) and returns null. That might not be the problem that you were encountering.

Debugging index bindings is a bit laborious. Instead, you can test the binding’s logic in a Let statement with a specific document reference. For example (using the People collection from the index tutorials: Index tutorials | Fauna Documentation):

Let(
  {
    doc: Get(Ref(Collection("People"), "294693428421204480"))
  },
  Concat(
    [
      Select(["data","first"], Var("doc")),
      If(
        ContainsField("letter", Select("data", Var('doc'))),
        ToString(Select(["data","letter"], Var("doc"))),
        Select(["data","last"], Var("doc"))
      )
    ],
    " "
  )
)
'Alan B'

And again with a reference that does not contain the letter field:

Let(
  {
    doc: Get(Ref(Collection("People"), "294693428421202432"))
  },
  Concat(
    [
      Select(["data","first"], Var("doc")),
      If(
        ContainsField("letter", Select("data", Var('doc'))),
        ToString(Select(["data","letter"], Var("doc"))),
        Select(["data","last"], Var("doc"))
      )
    ],
    " "
  )
)
'Leslie Lamport'