Reputation: 168
I am new to mongodb. I am trying to lookup 2 collections with the search parameter provided.
2 collection has the following structure:
servicetypes
_id:ObjectId(5ede7d9552d21c000436ac52)
TypeId:"1"
ServiceTypeTitle:"Body and Frame"
__v:0
servicesubtypes
_id:ObjectId(5ede85003bdd1c0004f26e71)
TypeId:"1"
SubTypeId:"1"
ServiceSubTypeTitle:"Air dam repaired"
__v:0
I tried to use regex and pipeline but I am not achieving what I want. Following is the code that I wrote.
route.get('/FilterServices/:text', async (req, res) => {
var text = req.params.text
var list = await ServiceType.aggregate([
{
$lookup: {
from: "servicesubtypes",
localField: "TypeId",
foreignField: "TypeId",
as: "ServiceSubTypes"
}
},
{ "$match": { "ServiceSubTypes.ServiceSubTypeTitle": {$regex: text, $options:"i"} } }
]);
console.log(list)
res.send(list)
});
This returns me the data in the following manner:
[
{
_id: 5ede7d9552d21c000436ac52,
TypeId: '1',
ServiceTypeTitle: 'Body and Frame',
__v: 0,
ServiceSubTypes: [
[Object], [Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object], [Object],
...100 more items
]
},
{
_id: 5ede7d9652d21c000436ac53,
TypeId: '2',
ServiceTypeTitle: 'Brakes',
__v: 0,
ServiceSubTypes: [
[Object], [Object], [Object], [Object], [Object], [Object],
[Object], [Object], [Object], [Object], [Object], [Object],
...100 more items
]
},
{I have 5 more items in ServiceType but are not added due to regex}
]
with the code above if it finds the value it returns me the entire ServiceSubTypes array for particular ServiceType. If it doesn't find it then ServiceType is not added in the list.
If the match is found then I only want that particular record in the ServiceSubTypes array. i.e
if I the search paramter is sunvisor then the result should be like
[
{
_id: 5ede7d9652d21c000436ac5a,
TypeId: '9',
ServiceTypeTitle: 'Vehicle',
__v: 0,
ServiceSubTypes: [
{
"_id": "5ede85683bdd1c0004f274d8",
"TypeId": "9",
"SubTypeId": "75",
"ServiceSubTypeTitle": "Right sunvisor replaced",
"__v": 0
},
{
"_id": "2ede8683dsaddc0004f2we4d8",
"TypeId": "9",
"SubTypeId": "75",
"ServiceSubTypeTitle": "Right sunvisor replaced",
"__v": 0
},
]
]
Upvotes: 1
Views: 2672
Reputation: 17925
In MongoDB, when you use $match
on an array - you would get entire array if at-least one object in the array satisfies the match criteria (not just the matching object but all objects will be retained) & eventually the document contains that array.
{I have 5 more items in ServiceType but are not added due to regex}
As I've said earlier, for these 5 documents in the ServiceType
collection there is no object in ServiceSubTypes
array that satisfies the condition in $match
.
Since we already know it would get entire array then how do we get only matched objects in an array in aggregation ? It can be done by using aggregation operator $filter. After $match
stage you can have $addFields
stage with $filter
on ServiceSubTypes
array to retain only matched objects in array i.e; to get desired result.
But in another way : if we can control the data that is being retrieved into ServiceSubTypes
array from servicesubtypes
collection, then we don't have to do these additional steps :
You can use specify-multiple-join-conditions-with-lookup instead of original $lookup
:
Modified Query :
[
{
$lookup: {
from: "servicesubtypes",
let: { typeId: "$TypeId" },
pipeline: [
{ $match: { $expr: { $eq: ["$TypeId", "$$typeId"] } } },
{ $match: { ServiceSubTypeTitle: { $regex: text, $options: "i" } } }
],
as: "ServiceSubTypes",
}
},
{ $match: { ServiceSubTypes: { $ne: [] } } }
]
Upvotes: 1