How to search for partial match using index in fauna db

479 Views Asked by At

I have a faunadb collection of users. The data is as follows:

{
    "username": "Hermione Granger",
    "fullName": "Hermione Jean Granger",
    "DOB": "19-September-1979",
    "bloodStatus": "Muggle-Born",
    "gender": "Female",
    "parents": [
      "Wendell Wilkins",
      "Monica Wilkins"
    ]
}

when I use an index I have to search for the whole phrase i.e. Hermione Granger. But I want to search for just Hermione and get the result.

2

There are 2 best solutions below

0
eskwayrd On

The Match function only applies an exact comparison. Partial matches are not supported.

One approach that might work for you is to store fields that would contain multiple values that need to be indexed as arrays.

When you index a field whose value is an array, the index creates multiple index entries for the document so that any one of the array items can be used to match entries. Note that this strategy increases the read and write operations involved.

Here's an example:

> CreateCollection({ name: "u" })
{
  ref: Collection("u"),
  ts: 1618532727920000,
  history_days: 30,
  name: 'u'
}
> Create(Collection("u"), { data: { n: ["Hermione", "Granger"] }})
{
  ref: Ref(Collection("u"), "295985674342892032"),
  ts: 1618532785650000,
  data: { n: [ 'Hermione', 'Granger' ] }
}
> Create(Collection("u"), { data: { n: ["Harry", "Potter"] }})
{
  ref: Ref(Collection("u"), "295985684233060864"),
  ts: 1618532795080000,
  data: { n: [ 'Harry', 'Potter' ] }
}
> Create(Collection("u"), { data: { n: ["Ginny", "Potter"] }})
{
  ref: Ref(Collection("u"), "295985689713967616"),
  ts: 1618532800300000,
  data: { n: [ 'Ginny', 'Potter' ] }
}
> CreateIndex({
  name: "u_by_n",
  source: Collection("u"),
  terms: [
    { field: ["data", "n"] }
  ]
})
{
  ref: Index("u_by_n"),
  ts: 1618533007000000,
  active: true,
  serialized: true,
  name: 'u_by_n3',
  source: Collection("u"),
  terms: [ { field: [ 'data', 'n' ] } ],
  partitions: 1
}
> Paginate(Match(Index("u_by_n"), ["Potter"]))
{
  data: [
    Ref(Collection("u"), "295985684233060864"),
    Ref(Collection("u"), "295985689713967616")
  ]
}

Note that you cannot query for multiple array items in a single field:

> Paginate(Match(Index("u_by_n"), ["Harry", "Potter"]))
{ data: [] }

The reason is that the index has only one field defined in terms, and successful matches require sending an array having the same structure as terms to Match.

To be able to search for the full username and the username as an array, I'd suggest storing both the string and array version of the username field in your documents, e.g. username: 'Hermione Granger' and username_items: ['Hermione', 'Granger']. Then create one index for searching the string field, and another for the array field, then you can search either way,

0
Kim On

I came across a solution that seems to work.

The below uses the faunadb client.

"all-items" is an index setup on a collection in Fauna that returns all items in the collection

The lambda is searching on the title field

This will return any document with a title that partially matches the search term.

I know this is a bit late; I hope it helps anyone else who may be looking to do this.

const response = await faunaClient.query(
    q.Map(
        q.Filter(
            q.Paginate(q.Match(q.Index("all_items"))),
            q.Lambda((ref) =>
                q.ContainsStr(
                    q.LowerCase(
                        q.Select(["data", "title"], q.Get(ref))
                    ),
                    title // <= this is your search term
                )
            )
        ),
        q.Lambda((ref) => q.Get(ref))
    )