Find - $text search with $or + other optional values

I can’t get to query multiple optional values on several fields. Here is my code:

if (query1 || query2 || query3 || query4) {

      const examples = await db

         .collection("examples")

         .find({

            $or: [

               {

                  $text: { $search: `${query1}` },

               },

               { field2: query2 },

               { field3: query3 },

               { field4: { $gte: Number(query4) } },

            ],

            verified: true,

         })

         .project({ anotherField: 0})

         .sort({ createdAt: -1 })

         .toArray();

      return {

         props: {

            examples: JSON.parse(JSON.stringify(examples)),

         },

      };

   }

I receive the following error message:

MongoServerError: error processing query: ns=examplesdb.examplesTree: $and
$or
field3 $eq null
field2 $eq “some-keyword”
field4 $gte nan.0
TEXT : query=undefined, language=english, caseSensitive=0, diacriticSensitive=0, tag=NULL
verified $eq true
Sort: { createdAt: -1 }
Proj: { anotherField: 0 }
planner returned error :: caused by :: No query solutions

Expected outcome:
Whichever query1 or 2 or 3 or 4 comes in, I want mongodb to find that document where query1 or 2 or 3 or 4 matches with $text or field2 or field3 or field4 (respectively).

The important thing is that the query1/2/3/4 are optional and sometimes all of them would be used, sometimes only 2 and so on… So my question points at $or as well.

I already know that $text search can’t be used with $or. And I’m on the free tier at the moment so I can’t use aggregation either (due to limitations, it returns that error message).

What else should I try? Please someone lead me in the right direction.

Thank you!

The main issue with your code is you *OR your 4 queries but you use all of them even if only one is true.

You have to test each query indivudually and build your complete $or array accordingly. This is standard JS because the $or field is a standard JS array where each clause is a standard JS object.

I have a solution that works. I think it’s similar to what you advised.

let filter = { verified: true };

if (query1) filter = { ...filter, $text: { $search: `${query1}` } };
if (query2) filter = { ...filter, field2: query2 };
if (query3) filter = { ...filter, field3: query3 };
if (query4) filter = { ...filter, field4: { $gte: Number(query4) } };

const examples = await db
  .collection('examples')
  .find(filter)
  .project({ anotherField: 0 })
  .sort({ createdAt: -1 })
  .toArray();

return {
  props: {
    examples: JSON.parse(JSON.stringify(examples)),
  },
};
1 Like

It is what I had in mind.

edited

Just note that in the new code you are ANDind the optional queries while you were ORing in the original.

1 Like

Great!

Actually you’re right. I need to and them after all. The query comes from the url. And that changes frequently. Just realized that’s the correct method, took so long… :grinning:

1 Like