C++ and aggregation

90 views
Skip to first unread message

Jeff Abrahamson

unread,
Nov 20, 2017, 8:23:19 AM11/20/17
to mongodb-user

I'm trying to do an aggregation using the C++ driver.  I've done successful find()'s, so I'm not totally confused, at least on setup.  And I can do the aggregation at the commandline, see bottom.

When I get to the last line in my example, below, I crash with a signal 11.  No error message to go on.  In the real code, I've wrapped myself in a try..catch(mongocxx::exception), but I never get to stack unwind, just SIGSEGV.

This lack of error message is making it tricky for me to develop debugging strategies.  Maybe I've borked my mongo request (but see further below for the request that works that I think I'm copying).

Any suggestions?

    mongocxx::collection email_events = mongo_db["email_events"];
    mongocxx::pipeline stages;
    bsoncxx::builder::stream::document match_stage, group_stage, project_stage;
    match_stage << "group_id" << to_string(group_id.GroupId())  //
                << "event"
                << "processed"  //
                << "category"
                << "focus-group-sync-reminder"  //
                << "user_id" << open_document << "$exists" << 1
                << close_document;
    group_stage << "_id" << open_document << "user_id"
                << "$user_id" << close_document  //
                << "time" << open_document << "$max"
                << "$time" << close_document;
    project_stage << "category"
                  << "$category"  //
                  << "event_type"
                  << "$event"  //
                     "epub_id"
                  << "$epub_id"  //
                     "focus_group_id"
                  << "$focus_group_id"  //
                     "user_id"
                  << "$user_id"  //
                     "time"
                  << "$timestamp";
    stages.match(match_stage.view())
        .group(group_stage.view())
        .project(project_stage.view());
    mongocxx::cursor cursor = email_events.aggregate(stages);
  // <-- Crashes here.

Fwiw, this is my stack crawl from that line, above:

    #0  0x00007ffff335e629 in mongoc_set_get_item () from /usr/local/lib/libmongoc-1.0.so.0
    #1  0x00007ffff336535b in _mongoc_topology_description_monitor_opening () from /usr/local/lib/libmongoc-\
    1.0.so.0
    #2  0x00007ffff3362be0 in mongoc_topology_select_server_id () from /usr/local/lib/libmongoc-1.0.so.0
    #3  0x00007ffff334324d in _mongoc_cluster_stream_for_optype () from /usr/local/lib/libmongoc-1.0.so.0
    #4  0x00007ffff3346f7e in mongoc_collection_aggregate () from /usr/local/lib/libmongoc-1.0.so.0
    #5  0x00007ffff5b5ef64 in mongocxx::v_noabi::collection::aggregate(mongocxx::v_noabi::pipeline const&, m\
    ongocxx::v_noabi::options::aggregate const&) () from /usr/local/lib/libmongocxx.so._noabi
    #6  0x000000000054bcdc in analytics::(anonymous namespace)::FetchSyncReminders (mongo_db=..., group_id=.\
    ..) at src/user_progress.cc:163

Just for comparison, this is the query I mean to do (up to "284" being a variable in the code above).  It works just fine.

    db.email_events.aggregate([
        { "$match": {
        'focus_group_id': '284',
            'event'     :     'processed',
            'category':       'focus-group-sync-reminder',
            'user_id':         {'$exists': 1},
        } },
        { '$project': {
            'category':       "$category",
            'event_type':     "$event",
            'epub_id':        "$epub_id",
            'focus_group_id': "$focus_group_id",
            'user_id':        "$user_id",
            'time':           "$timestamp"
        } },
        { '$group': {
            '_id': {
                'user_id':        "$user_id",
            },
            'time':           {"$max": "$time"}
        } }
    ])

-- 

Jeff Abrahamson
+33 6 24 40 01 57
+44 7920 594 255

http://p27.eu/jeff/

Jeff Abrahamson

unread,
Nov 20, 2017, 10:18:46 AM11/20/17
to mongodb-user
I have an answer why I was crashing (and it is the classic one: I first destroy the thing I am going to use).

I have a function that initialises my access to mongodb.

    mongocxx::database MongoInit(const MongodbSpec& mongo_spec) {
        LOGGABLE;
        mongocxx::instance instance{}; // This should be done only once.
        ostringstream uri_str;
        uri_str << "mongodb://" << mongo_spec.db_username << ":"
                << mongo_spec.db_password << "@" << mongo_spec.db_hostname << ":"
                << mongo_spec.db_port << "/" << mongo_spec.db_name << "?ssl=true";
        LOG_INFO << uri_str.str();
        mongocxx::uri uri(uri_str.str());

        mongocxx::options::client client_options;
        mongocxx::options::ssl ssl_options;
        ssl_options.allow_invalid_certificates(true);
        client_options.ssl_opts(ssl_options);

        return client["my_dbname"];
    }


Now, of course, I was thinking (dufusly) that the database handle would be passed back by NRVO, and so all is ok.  But, of course, the client is destroyed, and so the database isn't really part of anything anymore.

And so this minor change does what I need

    mongocxx::database MongoInit(mongocxx::client& client,
                                 const MongodbSpec& mongo_spec) {
        LOGGABLE;
        mongocxx::instance instance{};  // This should be done only once.
        ostringstream uri_str;
        uri_str << "mongodb://" << mongo_spec.db_username << ":"
                << mongo_spec.db_password << "@" << mongo_spec.db_hostname << ":"
                << mongo_spec.db_port << "/" << mongo_spec.db_name << "?ssl=true";
        LOG_INFO << uri_str.str();
        mongocxx::uri uri(uri_str.str());

        mongocxx::options::client client_options;
        mongocxx::options::ssl ssl_options;
        ssl_options.allow_invalid_certificates(true);
        client_options.ssl_opts(ssl_options);

        client = mongocxx::client(uri, client_options);
        return client["my_dbname"];
    }

I'll go back to coding under my rock now...

Jeff
http://p27.eu/jeff/
Reply all
Reply to author
Forward
0 new messages