3

Following is a piece of code where I am trying to query mongodb using mongocxx driver.

/*Code for finding all that match the filter */

mongocxx::cursor cursor = collection.find(
    document{} << "Vehicle_Registration" << vReg
    << "Vehicle_Make" << vMake
    << "Vehicle_Model" << vModel 
    << "Vehicle_Owner" << vOwner 
    << finalize);

Here

Vehicle_Registration, Vehicle_Make, Vehicle_Model, Vehicle_Owner

are fields of the collection.

The value of

vReg, vMake, vModel , vOwner

are as specified by the user on the screen. If a user specifies only some (not all) of these values, then rest of the values remain NULL. To avoid search on NULL values I try to set them to a regular expression { $regex: /./ } so that the NULL values don't affect the search.

This regular expression works on mongo shell and all fields set to this regular expression get ignored and don't affect the search.

But in the code, to set this regular expression I do :

If (vReg == NULL) {  vreg = "{ $regex: /./ }"  }

and then pass vReg in the document{} as shown in the code at the top

document{} << "Vehicle_Registration" << vReg

Here vReg gets passed as a string "{ $regex: /./ }" (with quotes) and not as { $regex: /./ } (without quotes). As a result it is considered a string and not evaluated as a regular expression in the query and hence there are no search results.

Can somebody please help me know how to pass it as regular expression?

Thank you!

user1211
  • 1,507
  • 1
  • 18
  • 27
Programmer
  • 31
  • 2

2 Answers2

3

You'll need to make the regular expression clause a proper BSON subdocument, not a string. Fortunately, there's a shortcut for you with the bsoncxx::types::b_regex type, which expands to the subdocument when added to a BSON document.

Updated: To see how you could toggle the way you describe, here's an example that uses a ternary operator and then wraps the query string or the regular expression in a bsoncxx::types::value, which is a union type:

using namespace bsoncxx::builder::stream;
using namespace bsoncxx::types;

int main() {
    auto inst = mongocxx::instance{};
    auto client = mongocxx::client{mongocxx::uri{}};
    auto coll = client["test"]["regex_question"];
    coll.drop();

    std::string vModel;
    auto empty_regex = b_regex(".", "");

    coll.insert_one(document{} << "Vehicle_Make"
                               << "Toyota"
                               << "Vehicle_Model"
                               << "Highlander" << finalize);

    auto filter = document{} << "Vehicle_Make"
                             << "Toyota"
                             << "Vehicle_Model"
                             << (vModel.empty() ? value{empty_regex} : value{b_utf8{vModel}})
                             << finalize;

    std::cout << bsoncxx::to_json(filter) << std::endl;

    std::cout << "Found " << coll.count(filter.view()) << " document(s)" << std::endl;
}

That gives this output:

{ "Vehicle_Make" : "Toyota", "Vehicle_Model" : { "$regex" : ".", "$options" : "" } }
Found 1 document(s)
xdg
  • 2,975
  • 19
  • 17
  • Thanks for that reponse! That solves part of my problem. – Programmer Dec 13 '16 at 06:56
  • But the other part that still remains is that while building the document{} in the collection.find() code I cant check for each of the fields (vReg/vMake/...) whether they are NULL or not and accordingly send either "vReg" string or the empty_regex. I want to keep the code generic so trying to see if there a common type that can hold both string value/regular expression that I can use instead of using string variables vReg/vMake/... while building the document. Thanks! – Programmer Dec 13 '16 at 07:11
  • I've updated the example to show you one way you could do it. – xdg Dec 15 '16 at 20:58
0

Just add another Example of making case-insensitive find by b_regex as xdg's answer has pointed out:

collection.find(
    bsoncxx::builder::stream::document{} 
        << KEY_VALUE 
        << open_document 
        << "$regex"
        << bsoncxx::types::value{bsoncxx::types::b_regex{"^" + tag, "i"}}
        << close_document 
        << finalize
);

It annoys me that the MongoDB manual says it should be { <field>: { $regex: /pattern/, $options: '<options>' } }, but actually the slash/ around /pattern/ is not needed here.

Eric
  • 11
  • 5