skip to Main Content

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.

2

Answers


  1. Chosen as BEST ANSWER

    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" });
      }
    });
    

  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search