Reputation: 696
I am trying to implement a search of documents in a collection. One of the queries in the $match stage checks if anything in a list matches another list from my JS (not within the document).
However, what I want to do is only run that query if the list has contents. If it is empty then just ignore it.
Essentially like choosing options in a filter. If you choose something, then it will search for that, if you choose nothing then it doesn't limit based on that.
Person documents:
{
name: String,
dob: Date,
gender: String,
favoriteColors: [{
color: String,
otherInfo: String
}]
}
My pipeline:
let colors = ["red", "blue", "green"];
collection.aggregate([
{$match: {
gender: "male",
//run below only if colors array is not empty
favoriteColors: {
$elemMatch: {
color: {
$in: colors
}
}
}
}}
])
How can I basically just run that part of the aggregate only if the array is not empty? I really don't want to use an if statement and write that same aggregate twice based on the two different conditions. Is it even possible to do this?
Upvotes: 1
Views: 609
Reputation: 22296
You can use something like this using $cond like so:
let colors = [ ... ]
db.collection.aggregate([
{
$match: {
$expr: {
$and: [
{
$eq: [
"$gender",
"male"
]
},
{
$cond: [
{
$gt: [
colors.length,
0
]
},
{
$gt: [
{
$size: {
$setIntersection: [
{
$map: {
input: "$favoriteColors",
as: "color",
in: "$$color.color"
}
},
colors
]
}
},
0
]
},
{}
]
}
]
}
}
}
])
But if you're already using code why not move the same logic into js?:
let colors = [ ... ];
let conds = [
{
"gender": "Male"
}
];
if (colors.length) {
conds.push({
"favoriteColors.color": {$in: colors}
})
}
db.collection.aggregate([
{
$match: {
$and: conds
}
}
])
Upvotes: 1