Home > Net >  Node.js Express case-insensitive search (filter) through MongoDB database
Node.js Express case-insensitive search (filter) through MongoDB database

Time:06-02

I want to make case-insensitive search API (I am using Express, Mongoose and Angular). I have datatable in my Angular application and Input field. So my API should return me data by (onChange). I have two collections (containers and containerstypes). I want it to work exactly the same as this example:https://www.w3schools.com/jquery/jquery_filters.asp?fbclid=IwAR3klbA6BJQ_a3wTRf8legaucd4S_2Ns6j8QGQjElgVCrEbde6HT3DSZz38

This search API returns me the right data fields (owner, identificationNo and manufacturer, which is in separate collection, but I sucessfully get it from other collection). But this API which I listed down returns me data when i write FULL STRING, it doesn't work by writing letters.

router.get("/search", async (req, res) => {
  try {
    const { searchString } = req.body;

    const containers = await Container.aggregate([
      {
        $lookup: {
          from: "containerstypes",
          localField: "containerTypeID",
          foreignField: "_id",
          as: "containerTypes",
        },
      },
      { $unwind: "$containerTypes" },

      {
        $match: {
          $or: [
            { owner: searchString },
            { IdentificationNo: searchString },
            { "containerTypes.manufacturer": searchString },
          ],
        },
      },
    ]);
    res.status(200).json(containers);
  } catch (err) {
    res.status(404).json({ success: false, msg: "Container not found" });
  }
});

Thanks everyone for help. I used here aggregation, but if it is possible, I can make it without aggregation framework. For only listing data in my table i used find and populate functions.

CodePudding user response:

It is better to create a text index on the fields you are searching on. in your model file you can create the index this way,

schema.index({owner: 'text', IdentificationNo: 'text'});
schema.index({'containerTypes.manufacturer': 'text'});

for searching use the $text and the $search operators,

await Container.find({$text: {$search: searchString }});

The issue here is that you can't use $text inside the aggregation function, it is only allowed as the first stage in the pipeline which is not useful for your case.

I would suggest embedding the containersType collection inside the containers collection if possible

CodePudding user response:

I found a solution. I just included $regex before every SearchString. For now it works, but I would appreciate, since I don't have much real world experience, if someone could tell me, if this is good solution or no.

router.get("/search", async (req, res) => {
  try {
    const { searchString } = req.body;

    const containers = await Container.aggregate([
      {
        $lookup: {
          from: "containerstypes",
          localField: "containerTypeID",
          foreignField: "_id",
          as: "containerTypes",
        },
      },
      { $unwind: "$containerTypes" },
      {
        $match: {
          $or: [
            { owner: { $regex: searchString, $options: "i" } },
            { IdentificationNo: { $regex: searchString, $options: "i" } },
            {
              "containerTypes.manufacturer": {
                $regex: searchString,
                $options: "i",
              },
            },
          ],
        },
      },
    ]);
    res.status(200).json(containers);
  } catch (err) {
    res.status(404).json({ success: false, msg: "Container not found" });
  }
});
  • Related