I am using the c++ client to ingest some data, but I am running into some problems with how to implement missing columns.
In python, I can have a dict of columns like so:
{“price1”: 10.0, “price2”:10.1}
And if price2 is not available, I can do:
{“price1”:10.0, “price2”:None}
Which I understand it is equivalent to:
{“price1”:10.0}
I can just pass my dict as the columns argument to sender.rows
and it transparently sends the rows, with or without missing columns, to the server.
I am having some trouble with replicating this in C++ and I have been looking into how to do it with no luck, as the C++ client apparently does not allow for null columns to be passed.
How do you suggest that I implement this for “ragged” rows in cpp?
As per the QuestDB examples, in C++ you use a buffer as in:
buffer
.table("trades")
.symbol("symbol","ETH-USD")
.symbol("side","sell")
.column("price", 2615.54)
.column("amount", 0.00044)
.at(questdb::ingress::timestamp_nanos::now());
// To insert more records, call `buffer.table(..)...` again.
sender.flush(buffer);
You need to call at
at the end of the buffer so the data gets queued to be sent, but you can call symbol
and column
as many times as needed for each row, and you can do this conditionally.
The example below builds a vector with three rows, one of them with an empty column, then it iterates over the vector and checks if the optional price
column is null. If it is, it skips invoking column
for the buffer on that column.
#include <questdb/ingress/line_sender.hpp>
#include <iostream>
#include <chrono>
#include <vector>
#include <optional>
#include <string>
int main()
{
try
{
auto sender = questdb::ingress::line_sender::from_conf(
"http::addr=localhost:9000;username=admin;password=quest;retry_timeout=20000;");
auto now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
struct Row {
std::string symbol;
std::string side;
std::optional<double> price;
double amount;
};
std::vector<Row> rows = {
{"ETH-USD", "sell", 2615.54, 0.00044},
{"BTC-USD", "sell", 39269.98, 0.001},
{"SOL-USD", "sell", std::nullopt, 5.5} // Missing price
};
questdb::ingress::line_sender_buffer buffer;
for (const auto& row : rows) {
buffer.table("trades")
.symbol("symbol", row.symbol)
.symbol("side", row.side);
if (row.price.has_value()) {
buffer.column("price", row.price.value());
}
buffer.column("amount", row.amount)
.at(questdb::ingress::timestamp_nanos(nanos));
}
sender.flush(buffer);
sender.close();
std::cout << "Data successfully sent!" << std::endl;
return 0;
}
catch (const questdb::ingress::line_sender_error& err)
{
std::cerr << "Error running example: " << err.what() << std::endl;
return 1;
}
}