Lee Morgan
Lee Morgan

Reputation: 688

Match based on a field only with non-empty array

I am trying to do a filter on something. Here is a simplified layout of my Order model:

{
    merchant: <Reference to the merchant>,
    date: <Date Object>
    name: "Some order name",
    ingredients: [{
        ingredient: {data: "some data"}
        otherData: "some data"
    }]
}

I want to query the documents based on the ingredients that they contain. I have an array of items to search through "objectifiedIngredients". If it has ingredients in it, then I want to search for orders that contain that ingredient. If the array is empty, then I want to not do the query and just get all orders. "objectifiedIngredients" is a list of ObjectId's. Here is what I have so far:

      Order.aggregate([
            {$match:{
                merchant: new ObjectId(req.session.user),
                date: {
                    $gte: from,
                    $lt: to
                },
                ingredients: {
                    $elemMatch: {
                        ingredient: {
                            $in: objectifiedIngredients
                        }
                    }
                }
            }}
        ])

How can I run the $match on ingredients only if the array has elements in it? I have tried using $cond, but either it doesn't work here or I didn't use it right.

Upvotes: 0

Views: 65

Answers (2)

semperlabs
semperlabs

Reputation: 458

Try this

Order.aggregate([
            {$match:{
                merchant: new ObjectId(req.session.user),
                date: {
                    $gte: from,
                    $lt: to
                },
                ingredients: {
                    $ne: false
                }
            }}
        ])

You can check for more details here

Upvotes: 1

Lee Morgan
Lee Morgan

Reputation: 688

I figured this one out after some time. I didn't use Mongoose to solve it. What I did was to create JavaScript variables to store the queries that I wanted. So I used an if statement to set what query was stored.

let query = {};
if(objectifiedIngredients.length === 0){
    query = {$exists: true};
}else{
    query = {
        $elemMatch: {
            ingredient: {
                $in: objectifiedIngredients
            }
        }
    }
}

Order.aggregate([
    {$match:{
        merchant: new ObjectId(req.session.user),
        date: {
            $gte: from,
            $lt: to
        },
        ingredients: query
])

NOTE: the {$exists: true} part assumes that the ingredient array exists on the order. If it doesn't then it won't return that order.

Upvotes: 0

Related Questions