I'm writing a series of classes that wrap around the mongodb-cxx classes in order to conform them to the storage API of the rest of my application, which is written in Qt.
I don't need the full function set of Mongo, basically just CRUD: create, read, update, delete, and find, perhaps with a few more advanced parameters passed in (read/write concerns, etc).
I had wanted to create a wrapper class around mongocxx::cursor such that the results of a find() could be iterated "later", in the data format used by the storage API. By "later" I mean that the (wrapped) cursor is returned to an abstraction class that can iterate over the results and validate data against a schema, or entries can be skipped, or results can be sent in groups (asynchronously) to an end client, etc.
For instance, if I have: (this is abbreviated a little for the example)
using namespace mongocxx;
class QMongoClient
{
static instance _instance;
QMongoClient(QString url) : _client( uri( qPrintable(url) ) );
client _client;
QMongoDatabase operator[](QString d);
};
class QMongoDatabase
{
QMongoDatabase(database db) : _database(db);
database _database;
QMongoCollection operator [](QString c);
};
class QMongoCollection
{
QMongoCollection(collection c) : _collection(c);
collection _collection;
//create... same as insert()
//read... same as find_one()
//update... same as upsert() or update()
//delete...
//find... a query will be provided
QMongoCursor findAll() { cursor c = _collection.find({}); return QMongoCursor(c); };
};
class QMongoCursor
{
QMongoCursor(cursor c) : _cursor(c);
//copy/move/assign constructors needed, probably
cursor _cursor;
QString data(); //return document contents as JSON string, for instance
//begin() <-- iterator
//end() <-- iterator
};
I had hoped this method would work, and it does, up until the cursor, which throws a compiler error:
error: call to implicitly-deleted copy constructor of 'mongocxx::v_noabi::cursor'
The idea is to do something like:
QMongoClient client("mongodb://url...");
QMongoDatabase db = client["somedbname"];
QMongoCollection coll = db["somecollection"];
QMongoCursor c = coll.findAll();
//or more abbreviated:
QMongoCursor c = client["somedbname"]["somecollection"].findAll();
//iterate over c here as needed, or send it to another abstraction layer...
I think this is happening because mongocxx::cursor objects are not meant to be passed around, and when they fall out of scope they are destroyed.
For instance when QMongoCursor::findAll() finishes, the returned cursor is meant to be destroyed, and can't be copied in the QMongoCursor constructor.
It seems very inefficient for the findAll() function to retrieve all documents at that moment and return them (potentially unknown size of result set). I'd like to be able to retrieve results 10 at a time, for instance, and send them over the network to the end client in groups asynchronously.
So the question is/are:
- how do I keep a cursor alive, if it's being destroyed when it falls out of scope and has no copy/move constructor
- or how can I create a pointer to a cursor and know what its lifespan is and when to delete it
- is there another method for this that I'm missing? I've been looking in the documentation but not finding it.
I think I'm missing some c++ syntax or mechanism, like move assign or something like that.
Any ideas?