I'm attempting to build a document that looks like this:
{
"Name" : "Joe",
"Age" : 34,
"Some Array" : [
{ "index" : 1, "Some Var" : 12, "Flag" : false },
{ "index" : 2, "Some Var" : 13, "Flag" : true },
{ "index" : 3, "Some Var" : 14, "Flag" : false }
],
"Status" : "Employed"
}
and I've been somewhat successful using the streaming builders as long as I do it all in one shot like this:
using bsoncxx::builder::stream::document;
using bsoncxx::builder::stream::open_document;
using bsoncxx::builder::stream::close_document;
using bsoncxx::builder::stream::open_array;
using bsoncxx::builder::stream::close_array;
using bsoncxx::builder::stream::finalize;
bsoncxx::builder::stream::document ArrayDoc;
ArrayDoc << "Name" << "Joe"
<< "Age" << 34
<< "Some Array" << open_array << open_document
<< "index" << 1 << "Some Var" << 12 << "Flag" << false
<< close_document << open_document
<< "index" << 2 << "Some Var" << 13 << "Flag" << true
<< close_document << open_document
<< "index" << 3 << "Some Var" << 14 << "Flag" << false
<< close_document
<< close_array
<< "Status" << "Employed";
What I really need to do though, is build the subarray with a loop to fetch the various values from other data structures. When I try to break the building process into parts, I get compiler errors on the open_document
bsoncxx::builder::stream::document ArrayDoc;
ArrayDoc << "Name" << "Joe"
<< "Age" << 34
<< "Some Array" << open_array;
for (int i = 0; i < 4; i++)
{
ArrayDoc << open_document
<< "index" << i << "Some Var" << 12 << "Flag" << false
<< close_document;
}
ArrayDoc << close_array
<< "Status" << "Employed";
The above gets me:
error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const bsoncxx::v_noabi::builder::stream::open_document_type' (or there is no acceptable conversion)
What am I doing wrong?
Instead of using the document stream builder, I suggest using the basic builder so you can create the different parts of the document as needed. In your case, you have several key/value pairs and an embedded array of value lists. The change in your thinking is to create subdocuments and use those to build the overall document.
So if you have a two-dimensional array of data that will be presented as an array in your (final) document:
int values[5][3] =
{
{1, 12, 1},
{2, 13, 0},
{3, 14, 1},
{4, 15, 1},
{5, 16, 0}
};
then you should build this array as it's own (intermediate) document
bsoncxx::builder::basic::array some_array;
for (int i = 0; i < 5; i++)
{
auto these_values = bsoncxx::builder::basic::document{};
these_values.append(kvp("index", values[i][0]));
these_values.append(kvp("Some Var", values[i][1]));
these_values.append(kvp("Flag", (values[i][2] == 1 ? bsoncxx::types::b_bool{ true } : bsoncxx::types::b_bool{ false })));
some_array.append(these_values);
}
Now you can use some_array
as a subdocument in the overall document.
Here is a self-contained example that runs for me:
#include <string>
#include <sstream>
#include <iostream>
#include <mongocxx/client.hpp>
#include <mongocxx/instance.hpp>
#include <bsoncxx/builder/list.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/builder/basic/document.hpp>
#include <bsoncxx/builder/basic/helpers.hpp>
#include <bsoncxx/builder/basic/kvp.hpp>
#include <bsoncxx/builder/basic/array.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/string/to_string.hpp>
#include <mongocxx/exception/exception.hpp>
mongocxx::instance instance{};
int main()
{
int values[5][3] =
{
{1, 12, 1},
{2, 13, 0},
{3, 14, 1},
{4, 15, 1},
{5, 16, 0}
};
using bsoncxx::builder::basic::kvp;
using bsoncxx::builder::basic::make_array;
using bsoncxx::builder::list;
auto my_doc = bsoncxx::builder::basic::document{};
my_doc.append(kvp("Name", "Joe"));
my_doc.append(kvp("Age", 34));
bsoncxx::builder::basic::array some_array;
for (int i = 0; i < 5; i++)
{
auto these_values = bsoncxx::builder::basic::document{};
these_values.append(kvp("index", values[i][0]));
these_values.append(kvp("Some Var", values[i][1]));
these_values.append(kvp("Flag", (values[i][2] == 1 ? bsoncxx::types::b_bool{ true } : bsoncxx::types::b_bool{ false })));
some_array.append(these_values);
}
my_doc.append(kvp("Some Array", some_array));
my_doc.append(kvp("Status", "Employed"));
std::cout << "my_doc json: " << bsoncxx::to_json(my_doc.view()) << std::endl;
}
This gives the output
my_doc json: { "Name" : "Joe", "Age" : 34, "Some Array" : [ { "index" : 1, "Some Var" : 12, "Flag" : true }, { "index" : 2, "Some Var" : 13, "Flag" : false }, { "index" : 3, "Some Var" : 14, "Flag" : true }, { "index" : 4, "Some Var" : 15, "Flag" : true }, { "index" : 5, "Some Var" : 16, "Flag" : false } ], "Status" : "Employed" }