Hi People, need to know if can implement a text search from two different values in the same document.
Lets say, I have a document like these:
{
"ref": Ref(Collection("Planets"), "267081079730471443"),
"ts": 1590977548370000,
"data": {
"name": "Mercury",
"type": "TERRESTRIAL",
"color": "GREY"
}
},
And I want to apply a text search with any value of the name and type properties.
Is this possible with the ContainsStr function?
Hi @adinjesuha,
Do you want to perform a partial match on both terms at the same time or one at the time?
May you drop a simple query you are trying to write?
Luigi
Hi Luigi…
I tried to make a text search query on both properties, for example
{
"ref": Ref(Collection("Planets"), "267081079730471443"),
"ts": 1590977548370000,
"data": {
"name": "Mercury",
"type": "TERRESTRIAL",
"color": "GREY"
}
}
If a user want to make a search based on the name property or color property, a tried to use something like these example
Map( Filter ( Paginate( Match( Index("all_Planets"))),
Lambda("planetRef",
ContainsStr(
LowerCase(Select(["data","name"],Get(Var("planetRef")))), "ur"
)
)
), Lambda("planetRef", Get(Var("planetRef"))))
But due to ContainsStr function only accept one string value, how can implement something for both values?
If you have two indexes, one for Term name
and one for Term color
. Then Union
them. Then Paginate
the Set.
By name OR color
Paginate(
Union(
Match(Index('Planets_by_name'), 'ur'), // or `null` if not searching by name
Match(Index('Planets_by_color'), 'blue') // or `null` if not searching by color
)
)
[EDIT: I had at first said you need to use Distinct, but Union already removes duplicates]
By name AND color, you need to use Intersection
.
Paginate(
Intersection(
Match(Index('Planets_by_name'), 'ur'),
Match(Index('Planets_by_color'), 'blue')
)
)
If this is a UDF you can also include logic that simplifies the query if one value or the other is not included. This means more Compute time, but fewer Read Ops.
Query(
Lambda(
['name', 'color'],
If(IsNull(Var('name')),
/* ... query only for color */,
If(IsNull(Var('color')),
/* ... query only for name*/,
/* ... query for both*/,
)
)
)
)
It looks like (from other posts) you may be coming from starting with GraphQL and Fauna only. If you haven’t done a deep dive into FQL, then I cannot recommend it enough. There are awesome articles out there, like this series, which interestingly enough also queries planets by color… And specifically goes into how to combine Indexes.
Also, if you are coming straight from using GraphQL first, I still find it very helpful to upload a schema and then go in and inspect the FQL that was generated for the Indexes which manage relationships and filtering.
Thanks for your help, and yes, I came from just GraphQL, but I need to expand the functionality in my app, applying filters, sorting and make custom text search in different parts of the UI, think dive into FQL could help me with these needs.
@adinjesuha
You can create an index:
CreateIndex({name:'planetByNameColor',source:Collection("Planets"),values:[{field:['data','name']},{field:['data','color']},{field:['ref']}]})
{ ref: Index("planetByNameColor"),
ts: 1610097185410000,
active: true,
serialized: true,
name: 'planetByNameColor',
source: Collection("Planets"),
values:
[ { field: [ 'data', 'name' ] },
{ field: [ 'data', 'color' ] },
{ field: [ 'ref' ] } ],
partitions: 8 }
and query this way:
Paginate(
Filter(
Match('planetByNameColor'),
Lambda(['name','color','ref'],And( ContainsStr(LowerCase(Var('name')),'y'), ContainsStr(LowerCase(Var('name')),'y') ) )
)
)
Hope it helps.
Luigi