5

I want to create a dynamic mongodb query which insert each part of it's aggregation if the condition is true else don't inject that part.

For example I want to check if the time is between 1AM till 8AM If yes then pass in the defined array to the mongodb query else pass nothing.

if ($this->Not_in_1_8 == true) {
    $this->N_IN_1_8 = array('dont_show_between_1_n_8' => array('$ne' => true));
}else {
    $this->N_IN_1_8 = null;
}
$MidnightCheck = $this->N_IN_1_8;
$this->campaign = Bcamp::raw(function ($collection) use ($seat_category_list, $banner_size, $seat_filter_list, $gold_network, $MidnightCheck) {
    return $collection->aggregate([
        [
            '$match' => [
                '$and' => [
                    ["targets.cats" => [
                        '$in' => $seat_category_list
                        ]
                    ],
                    ['banners.' . $banner_size => [
                        '$exists' => true
                        ]
                    ],
                    ['href' => [
                        '$nin' => $seat_filter_list
                        ]
                    ],
                    ['targets.gold_network' => [
                        '$eq' => $gold_network
                        ]
                    ],
                    ['status' => [
                        '$ne' => "Low_Budget"
                        ]
                    ],
                    ['daily_budget_status' => [
                        '$ne' => "Low_Budget"
                        ]
                    ],
                    $MidnightCheck
                ]
            ]
        ],
        [
            '$project' => [
                'ab' => [
                    '$cmp' => [
                        '$budget', '$click_cost'
                    ]
                ]
            ]
        ],
        [
            '$match' => [
                'ab' => [
                    '$lt' => 1
                ]
            ]
        ]

    ]);
});

But In this example It will inject null into query and makes it wrong and I catch error : bad query: BadValue: $or/$and/$nor entries need to be full objects

I have changed it to $this->N_IN_1_8 = ''; still no success.

All I need a neutral variable or condition to pass in which does not affect on query if the condition if false. Any Idea?

FYI : I'm using Laravel 5.3 framework with jenssegers/laravel-mongodb package for working with mongodb

1 Answer 1

1

Prefering to keep the code structure as is i.e. when a pre-built array is not used in the condition code, you may keep $MidnightCheck as null and wrap the array with array_filter:

return $collection->aggregate([
[
    '$match' => [
        '$and' => array_filter([
            ["targets.cats" => ['$in' => $seat_category_list]],
            ['banners.' . $banner_size => ['$exists' => true]],
            ['href' => ['$nin' => $seat_filter_list]],
            ['targets.gold_network' => ['$eq' => $gold_network]],
            ['status' => ['$ne' => "Low_Budget"]],
            ['daily_budget_status' => ['$ne' => "Low_Budget"]],
            $MidnightCheck
        ])
    ]
// ...

Calling array_filter without a second argument will filter out all false values from the array, causing the unwanted $MidnightCheck will be gone.

What I think might be clearer would be to pre-prepare the conditions in the callback:

$conditions = [
    ["targets.cats" => ['$in' => $seat_category_list]],
    ['banners.' . $banner_size => ['$exists' => true]],
    ['href' => ['$nin' => $seat_filter_list]],
    ['targets.gold_network' => ['$eq' => $gold_network]],
    ['status' => ['$ne' => "Low_Budget"]],
    ['daily_budget_status' => ['$ne' => "Low_Budget"]],
];
if ($MidnighCheck) {
    $conditions[] = $MidnightCheck;
}
return $collection->aggregate([
    ['$match' => [ '$and' => $conditions ],]
])
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your educational answer - but when I go with the second option I get : Aggregate.php line 93: $pipeline is not a list (unexpected index: "$match")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.