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