Reputation: 2551
I am trying to build a dynamic $match: for my MongoDB aggregate
This is what I wish I could do:
var matchStr = "";
if (req.body.propertyID) {
matchStr += "property: { $in: properties },"
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
matchStr += "status : {$lte: 4},"
} else if (req.body.status) {
matchStr += "status : {$lte: req.body.status},"
}
matchStr += "checkin : {$gte: (checkin)}, checkout: {$lte: (checkout)}"
And this is what I end up doing:
Its so messy, and now I have to add even more statements to the $match which will give me even bigger if structures.
There has to be a better way to do this!
I hope someone out there has an idea how to build these dynamically without the "if hell :)"
if (req.body.propertyID & req.body.status=="ALL") {
var matchStr = {
$match: {
$and:
[{
property: { $in: properties },
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
} else if (!req.body.propertyID & !req.body.status) {
var matchStr = {
$match: {
$and:
[{
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
} else if ((req.body.status=="ACTIVE" || req.body.status=="NOPAY")) {
if (req.body.propertyID) {
var matchStr = {
$match: {
$and:
[{
property: { $in: properties },
status : {$lte: 4},
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
} else {
var matchStr = {
$match: {
$and:
[{
status : {$lte: 4},
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
}
} else {
if (req.body.propertyID) {
var matchStr = {
$match: {
$and:
[{
property: { $in: properties },
status : {$lte: req.body.status},
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
} else {
var matchStr = {
$match: {
$and:
[{
status : {$lte: req.body.status},
checkin : {$gte: (checkin)},
checkout: {$lte: (checkout)}
}]
}
}
}
}
UPDATE! - Almost got it now, except it puts the "myMatch" inside the mongoDB statement.
Here is the new code:
var myMatch = {
checkin: {$gte: checkin},
checkout: {$lte: checkout}
};
if (req.body.hasOwnProperty('propertyID')) {
var properties = req.body.propertyID.map(function (obj) {
return obj._id;
});
console.log("properties: " + properties);
myMatch["property"] = { "$in": properties };
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
myMatch["status"] = { "$lte": 4 };
} else if (req.body.hasOwnProperty('status')) {
myMatch["status"] = { "$lte": +req.body.status };
}
And here is a console log of that structure:
myMatch: {
"checkin": {
"$gte": 1473571600
},
"checkout": {
"$lte": 1596163600
},
"property": {
"$in": [
"PAP-720",
"ATL-D406",
"WAT-606"
]
},
"status": {
"$lte": 3
}
}
Here is where I inject the myMatch object:
bookingTable.aggregate([
{
$match: {
$and:
[{
myMatch
}]
}
},
And here is the final mongodb statement:
Mongoose:
booking.aggregate([
{ '$match': { '$and': [ { myMatch: { checkin: { '$gte': 1473571600 }, checkout: { '$lte': 1596163600 }, property: { '$in': [ 'PAP-720', 'ATL-D406', 'WAT-606' ] }, status: { '$lte': 3 } } } ] } },
Upvotes: 3
Views: 4713
Reputation: 151112
First thing you really need to note is that you almost never need to write an explicit $and
statements. It has a usage, but typically all expressions in a MongoDB query are already an "AND" operation.
The next thing is that the solution will look remarkably familiar:
var myMatch = {
checkin: checkin,
checkout: checkout
};
if (req.body.propertyID) {
myMatch["property"] = { "$in": properties };
}
if (req.body.status=="ACTIVE" || req.body.status=="NOPAY") {
myMatch["status"] = { "$lte": 4 };
} else if (req.body.hasOwnProperty('status')) {
myMatch["status"] = { "$lte": +req.body.status };
}
The property names are pretty normal so you could alternately do:
myMatch.property = { "$in": properties };
But this all comes down to basic manipulation of JavaScript objects. And it's pretty much the same in any dynamically typed language.
Then you can just do later:
{ "$match": myMatch }
And its done.
Upvotes: 3