How to use $regex in mongodb aggregation query within $match - node.js

I am trying to use the $regex within $match, its not returning the matching documents.
db.collection('MyCollection', function (err, collection) {
collection.aggregate([
{ $match: { 'Code': 'Value_01', 'Field2': { $regex: '/Value_2/g' } } },
{ $project: {
_id: 1,
CodeNumber: '$Code',
FieldName2: '$Field2'
}
}
], function (err, Result_doc) {
console.log(Result_doc);
}
});
Can anyone tell me where its going wrong or the correct syntax?
I even tried with replacing the
'Field2': { $regex: /Value_2/g }

As it says in the $regex docs you linked to, the two ways to do this are:
Field2: /Value_2/g
OR
Field2: { $regex: 'Value_2', $options: 'g' }
But I also tried your second attempt of 'Field2': { $regex: /Value_2/g } and that worked as well.
BTW, the g regex option doesn't make sense in this context as you just need one match anyway. Note that it isn't even listed in the $regex docs.

I got it working with the following code:
var Value_match = new RegExp('Value_2');
db.collection('MyCollection', function (err, collection) {
collection.aggregate([
{ $match: { Code: 'Value_01', Field2: { $regex: Value_match } } },
{ $project: {
_id: 1,
CodeNumber: '$Code',
FieldName2: '$Field2'
}
}
], function (err, Result_doc) {
console.log(Result_doc);
}
});
On pushing the object content to console using console.dir(Value_match) it prints out '/Value_2/'

Related

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

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

$or Operator in Mongoose

I am using the $or operator in mongoose for searching through the name and description fields of the database. I want to check if the queryWord string contains any part of the database field(s). This is the code I am using:
const query = {
$or: [
{ name: `/${body.queryWord}/i` },
{ description: { $regex: `/${body.queryWord}/i` } },
],
};
Food.find(query, (err, data) => {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send(data);
}
});
But it returns, only, an empty array!
Any help is greatly appreciated!
Thank You!
I think the problem is because you wrap the regular expression in ``, which is understood as a string. You can try this way:
const queryWordRegex = new RegExp(body.queryWord, "i");
const query = {
$or: [
{ name: { $regex: queryWordRegex } },
{ description: { $regex: queryWordRegex } },
],
};

check an array of string value with array of object in mongodb

I have array of strings like this
let fromHour = ['2.5','3','3.5']
let toHour = ['2.5','3','3.5']
I have an array of object saved in mongoDB
timeRange = [
{
from:'2.5',
to:'3'
},
{
from:'3',
to:'3.5'
}
]
I want to check if any of my array of string value exist in that object value
I have tried this but it give me this error ( Unrecognized expression '$match' )
checkAppoint = await Appointment.aggregate([
{
$project: {
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange: {
'$match': {
'from': { $in: fromHolder },
'to': { $in: toHolder },
},
},
},
},
]);
also I have tried this solution and it work for me but it take to much time so I am trying this with aggregate
checkAppoint = await Appointment.findOne({
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange:{$elemMatch:{
from:{$in:fromHolder},
to:{$in:toHolder}
}}
});
So anyone have a solution for that
Just try $elemMatch and $in operators,
using find() method
checkAppoint = await Appointment.find({
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
})
Playground
using aggregate() method
checkAppoint = await Appointment.aggregate([
{
$match: {
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
}
}
])
Playground
So I have found a way around to solve this problem and I will share the solution I used
First I want to minimize my request to mongodb so I am now making just one request that bring all the appointment with the required date
and I want to make it this way because my fromHour and toHour array will change many time through single request
helperArray => contains all the day I want to check it's range
let checkAppoint = await Appointment.find({
date: { $in: helperArray },
status: { $in: ['pending', 'on-going'] },
});
now inside my for loop I will go through that data
checkAppoint.filter((singleAppoint) => {
if (singleAppoint._doc.date === myScheduleFinal[k].date) {
singleAppoint._doc.timeRange.map((singleTime) => {
if (fromHolder.includes(singleTime.from)) {
busy = true;
}
});
}
});

Mongoose: Is it possible to make a query on all jsons that contain a substring?

I'm using mongoose and my schema is:
const DeliverySchema = new mongoose.Schema({
startPlace:{type: String,required: true},
endPlace:{type: String,required: true},
});
Assuming that the start and end fields contain places in google format: street and city. Is it possible to make a query given only the city and which returns all the JSON that have that city in start or end as substring?
So if my record is:
startPlace:"Milano, MI, Italia",
endPlace:"Roma,RM,Italia"
And my query has parameter:
startPlace:"Milano"
It return me the JSON.
Thank you so much.
DeliverySchema.aggregate([
{
$match: {
$or: [
{
startPlace: {
$regex: "Milano, ?.+, ?.+"
}
},
{
endPlace: {
$regex: "Milano, ?.+, ?.+"
}
}
]
}
}
])
db.collection.aggregate([{
$match: {
$or: [{
startPlace: {
$regex: ".*Milano.*"
}
},
{
endPlace: {
$regex: ".*Milano.*"
}
}
]
}
}])
Mongo Playground

Doing partial search with mongoose

I'm trying to get Mongoose to return results in a query when I only give a partial query. For example: I have a 'Company' schema that lists a bunch of companies. A document example:
{
"_id" : ObjectId("57aabeb80057405968de1539"),
"companyName" : "Vandelay Industries",
"owner" : "Ary Vandelay",
"inception" : 2012,
"__v" : 1
}
So if I do a search query like this:
Company.findOne(
{ companyName: Vandelay Industries }, function (err, company) {
if (company) {
//do stuff
}
});
This will produce the document. But If I do the following, I won't get a result:
Company.findOne(
{ companyName: Vandelay }, function (err, company) {
if (company) {
//do stuff
}
});
I would like to be able to do these sorts of partial searches and still get a result. Is there any way to do that with Mongoose?
In order to achieve this you can use a regex search to get the required result.
var searchKey = new RegExp('Vandelay', 'i')
Company.findOne({ companyName: searchKey }, function (err, company) {
if (company) {
//do stuff
}
});
Refer this stackoverflow post.
You can use this query to get result on specific value
Company.findOne({"companyName": /Vandelay/},function(err,company){
if(!err){
console.log(company);
}
});
To get result faster you should use indexing ref https://docs.mongodb.com/manual/text-search/.
db.Company.createIndex( { companyName: "text" } )
then you can search
db.Company.find( { $text: { $search: "company name" } } )
But this only support full word search not partial, so adding an extra line to this will help
db.Company.find({ $or: [
{ $text: { $search: query } },
{ companyName: { $regex: '^' + 'copmany name'} }
]}
This will help you search the results faster than normal
Are you doing a fulltext search? If you do that:
TagGroup.find({
$text: {
$search: text
}
}, {
score: {
$meta: "textScore"
}
}).sort({
score: {
$meta: 'textScore'
}
})
Try that code below. Also you need create a index on that schema
TagGroupSchema.index({
"$**": "text"
});
Here is the document
You can use elasticsearch to do that either, when the documents grows, you should consider this way.

Resources