Bandydan
Bandydan

Reputation: 631

MongoDb, Yii2, Active Record: $or needs an array

everyone.

I have composed the following query in mongo and tested it using robomongo - it worked.

db.customers.find({$or: [
    {emailaddress: /.*test.*/},
    {address: /.*test.*/},
    {firstname: /.*test.*/}
]})

Now I am trying to implement this query in Yii2 using Active Record:

$fields = [];
$search = '/.*' . $search . '.*/';//in $search was the word 'test'

foreach($this->searchFields as $field) {
    $fields["$field"] = "$search";
}
$text_search = [ '$or' => ['$search' => $fields]];

$query = $query->where($text_search);

$provider = new ActiveDataProvider([
    'query' => $query,
]);

It worked before adding $or, and now it gives me an error:

"name": "MongoDB Exception",
"message": "Cannot run command count(): exception: $or needs an array",
"code": 20,
"type": "yii\\mongodb\\Exception",

Printing $test_search using print_r gives me:

Array
(
    [$or] => Array
    (
        [$search] => Array
        (
            [emailaddress] => : /.*test.*/
            [address] => : /.*test.*/
            [firstname] => : /.*test.*/
        )
    )
)

If I remove '$search' => and leave only

$text_search = [ '$or' => [$fields]];

it gives me:

{
    "recordsTotal": 0,
    "recordsFiltered": 0,
    "data": []
}

Does anyone know how to make this query working in Active Record? Please give me some ideas.

Thanks in advance.

Upvotes: 1

Views: 1085

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50416

You are missing that each "document" is meant to be a member of the $or array as it's own condition. You are making a single document with the different keys.

Also you cannot use a regular expression from a "string" like that. Rather use the $regex query operator, with just the string of the expression.

Instead do:

$search = '.*' . $search . '.*';
$text_search = [ '$or' => [] ];

foreach($this->searchFields as $field) {
    array_push( $text_search['$or'], [ $field => [ '$regex' => "$search" ] ] );
}

$query = $query->where($text_search);

Also when you compare to JSON then output as JSON encoded for debugging purposes:

echo json_encode( $text_search, JSON_PRETTY_PRINT ) . "\n";

You can't go wrong then as you will see if it looks the same or not:

{
    "$or": [
        {
            "emailaddress": { "$regex": ".*test.*" }
        },
        {
            "address": { "$regex": ".*test.*" }
        },
        {
            "firstname": { "$regex": ".*test.*" }
        }
    ]
}

Upvotes: 2

Related Questions