fullText queries not working

i am trying to do string queries using the fullText method as per the documentation : https://docs.moralis.io/queries#full-text-search

for instance I am trying to use the fullText query method on the javascript console inside the moralis db, i am using the following code:

let obj = "Services";
let objKey = "category";
let searchQuery = "air";

const Services = Parse.Object.extend(obj);
let query = new Parse.Query(Services);
query.fullText(objKey,searchQuery);
let results = await query.find();
console.log(results);

OR

let obj = "Services";
let objKey = "category";
let searchQuery = "air";
const Services = new Parse.Object(obj);
const query = new Parse.Query(Services);
query.fullText(objKey,searchQuery);
query.ascending('$score');
query.select('$score');
query.find().then(function(results) {
    // results contains a weight / rank in result.get('score')
    console.log(results);
  })
  .catch(function(error) {
    // There was an error.
    console.log(error);
  });
  
console.log("query",query)

however it doesnt seem as though my objects keys are being indexed as I am not getting any results returned.
how can we index our objects keys like with MongoDB?

any help would be really appreciated as my app pretty much wont work as intended without this functionality.

Thanks

Can you post a screenshot of your DB?
Also what server URL?

I used your code to do a query on a test DB and it does work, probably some small error here, maybe its the type of column - is “category” column a string?

hi Ivan thanks for your response. I did manage to get it working in the end, but its not querying as well as I had hoped, like i was hoping it to catch all words or parts of words in my query, eg search for air, and im expecting airport or airbag or airplane etc to be returned. but I may be expecting a bit much.

my server URL is https://qqcsb1l0fe2o.moralis.io:2053/server

Is there any way to make fullText search over more than 1 column string? for instance I would like fullText to search of column strings: category, subCategory, title, description

Thank you in advance!

Try query.matches instead of query.fullText for partial matches.

Regarding several column - try to do several query.matches on same query, I haven’t tried it but could work. Try and let me know!

1 Like

thank you Ivan,
can you please point me to which match method you are referring to specifically? in the documentation i can see the Match in the pipeline aggregate queries section, but I have tried it and you have to be very precise with your search term for it to work which doesnt seem too useful.

Also is there a way where i can check with column strings have been indexed for fullText search? I seem to be able to search through my ‘category’ column only, ideally id like to be able to index other columns as well if its possible.

We dont have full docs for this yet but just replace word “fullText” with “matches”

1 Like

cool, between fullText and matches, i get close to what i need, thank u Ivan

1 Like

amazing, good luck, let us know if you need more help

Hy @phyx1u5 and @ivan,
I am also trying to query for more than one column so users can search for keywords in the name and description column from the same input field.
So far I can only make it work for one of them, but not both at the same time. Can you guide me the way?
I tried to do multiple query.matches on the same query, but then it returns just an empty array.

 const myObject= Moralis.Object.extend("myObject");
          const query = new Moralis.Query(myObject);
          query.matches("description", search);
          // query.fullText("name", search);
          let result = await query.find();

          console.log(result);

How to make this work so both columns will be queried?

Also interesting: for my description column, fullText will always return an empty array, only matches work, and matches need the exact match, the slightest difference (uppercase vs. lowercase) matters :thinking:

Any advice?

@malik will have some time tomorrow to experiment

For now a quick solution is probably separate 2 queries - does that work?

1 Like

for my app YouWho.io I ended up using matches and if that got 0 results I used if statement to run fulltext search which is like the best of both worlds. You can string multiple matches queries together with Moralis.Query.or(query1, query2, etc)

Not sure if this is the correct way to do it, its not elegant but it got the job done (mostly) for me…

const searchResults = async () => {
        await handleLocation();
        let geoPoint = new Moralis.GeoPoint(currLocRef.current);

        let Services = Moralis.Object.extend("Services");

        let queryTitle = new Moralis.Query(Services);
        queryTitle.matches("title", query);

        let queryCategory = new Moralis.Query(Services);
        queryCategory.matches("category", query);

        let querySubCategory = new Moralis.Query(Services);
        querySubCategory.matches("subCategory", query);

        let queryDescription = new Moralis.Query(Services);
        queryDescription.matches("description", query);

        let queryServices;

        if (query !== "" && query !== null) {

            await handleLocation();
            geoPoint = new Moralis.GeoPoint(currLocRef.current);

            queryServices = Moralis.Query.or(queryTitle, queryCategory, querySubCategory, queryDescription);

            queryServices.include("providerPublic");

            if (sortResults) {
                if (sortResults === "nearest") {
                    if (currLocRef.current[0] === 13.37 && currLocRef.current[1] === 13.37) {
                        setSortResults("rateDesc");
                        setNewServiceError(["Geolocation Failed", "Please allow location or GPS in your web-browser or device."]);
                        setShowAlert(true);
                        return;
                    } else {
                        try {
                            queryServices.near("location", geoPoint);
                        } catch (error) {
                            console.log(error)
                        }
                    }
                }

                if (sortResults === "rateDesc") {
                    queryServices.descending("rate");
                }

                if (sortResults === "rateAsc") {
                    queryServices.ascending("rate");
                }

                if (sortResults === "reviewDesc") {
                    queryServices.descending("updatedAt");
                }

                if (sortResults === "reviewAsc") {
                    queryServices.ascending("updatedAt");
                }

                if (sortResults === "newest") {
                    queryServices.descending("updatedAt");
                }

                if (sortResults === "oldest") {
                    queryServices.ascending("updatedAt");
                }
            };

            await queryServices.find()
                .then(async function (results) {

                    if (currLocRef.current[0] !== 13.37 && currLocRef.current[1] !== 13.37) {
                        for (let i = 0; i < results.length; ++i) {
                            results[i].distance = results[i].attributes.location.kilometersTo(geoPoint).toFixed(1);
                        }
                    };

                    setQueryResults(results);

                    if (results.length === 0) {

                        await handleLocation();
                        geoPoint = new Moralis.GeoPoint(currLocRef.current);

                        let queryCategoryText = new Moralis.Query(Services);
                        queryCategoryText.fullText("category", query);
                        queryCategoryText.include("providerPublic");

                        if (sortResults) {
                            if (sortResults === "nearest") {
                                if (currLocRef.current[0] === 13.37 && currLocRef.current[1] === 13.37) {
                                    setSortResults("rateDesc");
                                    setNewServiceError(["Geolocation Failed", "Please allow location or GPS in your web-browser or device."]);
                                    setShowAlert(true);
                                    return;
                                } else {
                                    try {
                                        queryServices.near("location", geoPoint);
                                    } catch (error) {
                                        console.log(error)
                                    }
                                }
                            }

                            if (sortResults === "rateDesc") {
                                queryCategoryText.descending("rate");
                            }

                            if (sortResults === "rateAsc") {
                                queryCategoryText.ascending("rate");
                            }

                            if (sortResults === "reviewDesc") {
                                queryCategoryText.descending("updatedAt");
                            }

                            if (sortResults === "reviewAsc") {
                                queryCategoryText.ascending("updatedAt");
                            }

                            if (sortResults === "newest") {
                                queryCategoryText.descending("updatedAt");
                            }

                            if (sortResults === "oldest") {
                                queryCategoryText.ascending("updatedAt");
                            }
                        };

                        await queryCategoryText.find()
                            .then(async function (results) {

                                if (currLocRef.current[0] !== 13.37 && currLocRef.current[1] !== 13.37) {
                                    for (let i = 0; i < results.length; ++i) {
                                        results[i].distance = results[i].attributes.location.kilometersTo(geoPoint).toFixed(1);
                                    }
                                };

                                setQueryResults(results);

                                if (results.length === 0) {

                                    await handleLocation();
                                    geoPoint = new Moralis.GeoPoint(currLocRef.current);

                                    let queryTitleText = new Moralis.Query(Services);
                                    queryTitleText.fullText("title", query);
                                    queryTitleText.include("providerPublic");

                                    if (sortResults) {
                                        if (sortResults === "nearest") {
                                            if (currLocRef.current[0] === 13.37 && currLocRef.current[1] === 13.37) {
                                                setSortResults("rateDesc");
                                                setNewServiceError(["Geolocation Failed", "Please allow location or GPS in your web-browser or device."]);
                                                setShowAlert(true);
                                                return;
                                            } else {
                                                try {
                                                    queryServices.near("location", geoPoint);
                                                } catch (error) {
                                                    console.log(error)
                                                }
                                            }
                                        }

                                        if (sortResults === "rateDesc") {
                                            queryTitleText.descending("rate");
                                        }

                                        if (sortResults === "rateAsc") {
                                            queryTitleText.ascending("rate");
                                        }

                                        if (sortResults === "reviewDesc") {
                                            queryTitleText.descending("updatedAt");
                                        }

                                        if (sortResults === "reviewAsc") {
                                            queryTitleText.ascending("updatedAt");
                                        }

                                        if (sortResults === "newest") {
                                            queryTitleText.descending("updatedAt");
                                        }

                                        if (sortResults === "oldest") {
                                            queryTitleText.ascending("updatedAt");
                                        }
                                    };

                                    await queryTitleText.find()
                                        .then(function (results) {

                                            if (currLocRef.current[0] !== 13.37 && currLocRef.current[1] !== 13.37) {
                                                for (let i = 0; i < results.length; ++i) {
                                                    results[i].distance = results[i].attributes.location.kilometersTo(geoPoint).toFixed(1);
                                                }
                                            };

                                            setQueryResults(results);

                                            if (results.length === 0) {

                                                setNoSearchResults(noResults);

                                            }
                                        })
                                }
                            })
                    }
                })
                .catch(function (error) {
                    // There was an error.
                    setNewServiceError(["Search Failed", error.message]);
                    setShowAlert(true);
                });

        } else {

            queryServices = new Moralis.Query(Services);

            await handleLocation();
            geoPoint = new Moralis.GeoPoint(currLocRef.current);

            if (sortResults) {
                if (sortResults === "nearest") {
                    if (currLocRef.current[0] === 13.37 && currLocRef.current[1] === 13.37) {
                        setSortResults("rateDesc");
                        setNewServiceError(["Geolocation Failed", "Please allow location or GPS in your web-browser or device."]);
                        setShowAlert(true);
                        return;
                    } else {
                        queryServices.near("location", geoPoint);
                    }
                }

                if (sortResults === "rateDesc") {
                    queryServices.descending("rate");
                }

                if (sortResults === "rateAsc") {
                    queryServices.ascending("rate");
                }

                if (sortResults === "reviewDesc") {
                    queryServices.descending("updatedAt");
                }

                if (sortResults === "reviewAsc") {
                    queryServices.ascending("updatedAt");
                }

                if (sortResults === "newest") {
                    queryServices.descending("updatedAt");
                }

                if (sortResults === "oldest") {
                    queryServices.ascending("updatedAt");
                }
            };

            if (who !== "" && who !== null) {
                const providerObject = Moralis.Object.extend("UserPublic");
                const queryProvider = new Moralis.Query(providerObject);
                queryProvider.equalTo("username", String(who))
                const userProvider = await queryProvider.first();
                queryServices.equalTo("providerPublic", userProvider);

            }

            queryServices.limit(50);
            queryServices.include("providerPublic");


            await queryServices.find().then(function (results) {
                // results contains a weight / rank in result.get('score')
                if (results.length === 0) {
                    setNoSearchResults(noResults);
                } else {
                    if (currLocRef.current[0] !== 13.37 && currLocRef.current[1] !== 13.37) {
                        for (let i = 0; i < results.length; ++i) {
                            results[i].distance = results[i].attributes.location.kilometersTo(geoPoint).toFixed(1);
                        }
                    };
                    setQueryResults(results);
                }
            })
                .catch(function (error) {
                    // There was an error.
                    setNewServiceError(["Search Failed", error.message]);
                    setShowAlert(true);
                });
        }

    }
1 Like

Thanks for the example @phyx1u5, also very nice app that you made! I will take a closer look into your example tomorrow and see if it will help me, thank you :slight_smile:
@ivan yes I did end up using different queries for now also, thank you.
Looking very much forward to see the react sdk evolve. Do you have any infos on when it will be production ready?

1 Like

It is production ready since 1st of June, but even though its production-ready it will always evolve
Production-ready means that we take great care not to have too many breaking changes and backup all data etc.

2 Likes

ok, I see thank you.