Thanks for providing the code. It isn't quite an
SSCCE though, as it doesn't have the necessary headers, and the code isn't wrapped in a main function. I've done that, and here is a complete repro of the behavior you are observing:
#include <cstdlib>
#include <iostream>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/pool.hpp>
#include <mongocxx/uri.hpp>
int main(int argc, char* argv[]) {
using bsoncxx::builder::stream::document;
mongocxx::instance mongo_driver{};
const auto uri = mongocxx::uri{(argc >= 2) ? argv[1] : mongocxx::uri::k_default_uri};
mongocxx::pool pool{uri};
auto conn = pool.acquire();
auto coll = (*conn)["test"]["test"];
coll.drop();
bsoncxx::oid id;
if (id)
std::cout << "id object is true-ish\n";
auto doc = bsoncxx::builder::stream::document{} << "_id" << id << bsoncxx::builder::stream::finalize;
std::cout << "doc before insert: " << bsoncxx::to_json(doc) << "\n";
coll.insert_one(doc.view());
for (auto&& c : coll.find({})) {
std::cout << "doc after insert: " << bsoncxx::to_json(c) << "\n";
bsoncxx::oid id1 = c["_id"].get_oid().value;
if (id1)
std::cout << "id field is true-ish\n";
}
return EXIT_SUCCESS;
}
When I run this program, I observe the following output:
doc before insert: {
"_id" : {
"$oid" : "d93a5eff7f000076f2c066ff"
}
}
doc after insert: {
"_id" : {
"$oid" : "d93a5eff7f000076f2c066ff"
}
}
id field is true-ish
The reason you observe this behavior is that you are invoking the default constructor of bsoncxx::oid, which very surprisingly does not initialize the byte array within the bsoncxx::oid object. This is why your first conditional, where you check if(id) does not take the true branch and print anything - the bsoncxx::oid object knows that it is uninitialized, and the bytes it contains are effectively random, so its operator bool returns false.
However, you then actually add those random bytes into your document for the _id field and store it into the database. As a result, when you query for the document, the object you get back contains a field called _id of the correct type to be extracted as a bsoncxx::types::b_oid type, containing the same random bytes that you added when you built the document. That object contains a bsoncxx::oid object which has been initialized, which is why the second conditional takes the true branch and results in a print.
The immediate workaround for your problem is to change your code as follows:
coll.drop();
bsoncxx::oid id{bsoncxx::oid::init_tag};
if (id)
Which will properly initialize the bsoncxx::oid object with meaningful values.
I did some digging in the git history for the project, and this behavior has been present in the bsoncxx::oid class since the beginning. I suspect that it was written this way so that writing:
bsoncxx::oid obj_id;
obj_id = some_document["_id"].get_oid().value;
didn't result in first doing the work to construct a valid OID representation for obj_id, and then immediately discard that result by assigning in the result of obtaining the OID from the document.
I don't think that is a very good argument though, since the behavior is so surprising. Most likely, the sense of the initialization should be reversed, and the default constructor should properly initialize the bytes. Users who want or need to avoid the overhead of constructing proper OID internals should explicitly request that behavior:
bsoncxx::oid obj_id{bsoncxx::oid::no_init_tag};
obj_id = some_doc["_id"].get_oid().value;
I've filed
https://jira.mongodb.org/browse/CXX-940 to track this issue. Thanks for posting the example that revealed this problem with the driver API. In the future, if you encounter issues like this, I strongly recommend posting a fully compilable example code demonstrating the problem. It will allow us to understand the issue you have encountered much more quickly than trying to describe it in prose.
Thanks,
Andrew