How to overcome the incompatibiliy of b_null
with other types in the bsoncxx library?
It's my understanding that null is the state of a value, and not the type of an value within the MongoDB ecosystem. That is an element should have a key that maps to a certain type of value, and that it's possible that value is null. But the C++ driver doesn't seem to comply with this.
What is the cleanest way to handle the possibility that an element is null using the bsoncxx library? I would think that all types should be convertible to null, but I cannot figure out if or how that would be the case. This is particularly difficult in converting std::optional
types into a comparable BSON type. Below is an example of some code that I would like to work, but I haven't been able to find a reasonable work around.
template<typename T>
static auto ToBsonType(const std::optional<T>& v) {
if (v.has_value()) {
return ToBsonType(v.value());
} else {
return bsoncxx::nullopt;
}
}
My serializer works like this, which works well for all types until I get to these nullable types:
static bsoncxx::document::value ToBsonDocument(Class class) {
auto doc = document{}
<< "_id" << ToBsonType(class.id())
<< "a" << ToBsonType(class.a())
<< "b" << ToBsonType(class.b())
<< finalize;
return doc;
}
Any suggestions, or do I need to rewrite the entire API if nullible types cannot be represented as a single type?
Answers
In the MongoDB ecosystem, null
is indeed considered a valid value that can be stored for any type. However, handling nullable types in BSON serialization/deserialization with the C++ driver's bsoncxx
library can be a bit tricky.
The approach you've taken in your ToBsonType
function is a good start, but the issue lies in converting std::optional<T>
into BSON. As of my last update, the bsoncxx
library doesn't directly support serializing std::optional
types to BSON.
One possible approach to handle nullable types is to define your own mapping from std::optional<T>
to BSON values. You can create overloaded functions for different types or use template specialization. Here's an example of how you might achieve this:
#include <bsoncxx/types.hpp>
#include <bsoncxx/types/value.hpp>
#include <optional>
bsoncxx::types::b_null ToBsonType(const std::nullopt_t&) {
return bsoncxx::types::b_null{};
}
template <typename T>
bsoncxx::types::b_value ToBsonType(const std::optional<T>& v) {
if (v.has_value()) {
return ToBsonType(v.value());
} else {
return bsoncxx::types::b_null{};
}
}
With this approach, you can handle nullable types like std::optional<int>
, std::optional<std::string>
, etc., without needing to rewrite your entire API.
Additionally, if you're using a newer version of the mongocxx
and bsoncxx
libraries, you might want to check their documentation or GitHub repository to see if support for serializing std::optional
types has been added since my last update. If so, you may be able to simplify your code by using the built-in support.