How to iterate or save mongodb element/array using Mongo C++ 11 driver

2,361 views
Skip to first unread message

Michael Lin

unread,
Jul 26, 2016, 10:23:04 AM7/26/16
to mongodb-user
I've been trying to rewrite my code to adapt the latest MongoDB C++ 11 Driver, and I run into some problem that I cant figure it out.

Let's say, I have a database like this

{
   
"_id" : -767958333,
   
"messagelist" : [ {
       
"uid" : 413098706,
       
"status" : 2,
       
"uniqid" : "413098706:1441105719"
   
} ]
}


I need to go into the "messagelist" field, and iterate each element under it.

At the old driver, I simply save it into a vector.
BSONObj bson_obj; (refer to the db above)
if (bson_obj.hasField("messagelist" && ((arr_value = bson_obj["messagelist"]).isNull())){
    vector
<BSONElement> msg_vec = arr_value.Array();
   
for (vector<mongo::BSONElement>::iterator it = message_vec.begin(); it != message_vec.end(); ++it) {
       
BSONObj msg_obj = it->embeddedObject();
       
// black magic happen here....
       
if (...) {
       
...
       
}
   
}
}


When it comes to the Mongo C+11 Driver, since the complete change of API, I've been reading the sample code and seraching online, still not working.

At the new driver, the code I have so far
// Library
...
...

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;
using namespace bsoncxx;
using namespace std;


int magic(bsoncxx::builder::stream::document* document) {

    document::value value{document->extract()};
    document::view view{value.view()};
    
    for (document::element ele : view) {
        if(ele.type() == type::k_array) {
            //@TODO
        }
    }
}

int
main() {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{"xxxx"}};
    bsoncxx::builder::stream::document document{};

    document << "_id" << "102030" 
         << "messagelist"
         << open_array 
         << open_document << "uid" << 23234234
         << "status" << 2 
         << "uniqid" << "1212" << close_document
         << close_array;
    int ret = magic(document);
}


I really appreciate your help! Thanks


David Golden

unread,
Jul 26, 2016, 12:25:33 PM7/26/16
to mongodb-user
Hi, Michael.

Here's an example that shows how you can iterate over a structure like you describe:

#include <cstdint>
#include <iostream>

#include <bsoncxx/array/view.hpp>
#include <bsoncxx/array/view.hpp>
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/document/value.hpp>
#include <bsoncxx/document/view.hpp>
#include <bsoncxx/json.hpp>
#include <bsoncxx/types.hpp>
#include <bsoncxx/types/value.hpp>

using namespace bsoncxx;

document
::value new_message(int64_t uid, int32_t status, std::string uniqueid) {
  builder
::stream::document doc;
 
return doc << "uid" << uid << "status" << status << "uniqueid" << uniqueid
             
<< builder::stream::finalize;
}

void iterate_messages(document::view doc) {
 
// extract "messagelist" element
  document
::element ele = doc["messagelist"];


 
// check validity && type before trying to iterate
 
if (ele && ele.type() == type::k_array) {
    array
::view subarray{ele.get_array().value};
   
for (array::element msg : subarray) {
      std
::cout << "array element: " << to_json(msg.get_value()) << std::endl;
   
}
 
} else {
    std
::cout << "Missing or invalid messagelist." << std::endl;
 
}
}

int main() {
  builder
::stream::document builder{};
  builder
<< "messagelist" << builder::stream::open_array
         
<< new_message(413098706, 2, "413098706:1441105719")
         
<< new_message(413098707, 2, "413098707:1441105720")
         
<< new_message(413098708, 2, "413098708:1441105721")
         
<< builder::stream::close_array;

  document
::value doc = builder << builder::stream::finalize;

  iterate_messages
(doc.view());
}


I hope that helps clarify.

Regards,
David

Michael Lin

unread,
Jul 27, 2016, 12:46:09 AM7/27/16
to mongodb-user
Hi David,

Thanks for the reply

I am sorry that my question is not clear.

I would like to access
{ 
        
"uid" : 413098706, 
        
"status" : 2, 
        
"uniqid" : "413098706:1441105719" 
    
}

Specificly, "uid", status", and "uniqid that I can check value of each one of them

Thansk you

Best,
Michael

David Golden

unread,
Jul 27, 2016, 9:36:42 AM7/27/16
to mongodb-user
Here's a revised "iterate_messages" function that shows element access and type checking (you should check the type before calling a "get_xxx" function on an element):

void iterate_messages(document::view doc) {
 
// extract "messagelist" element
  document
::element ele = doc["messagelist"];


 
// check validity && type before trying to iterate
 
if (ele && ele.type() == type::k_array) {
    array
::view subarray{ele.get_array().value};
   
for (array::element msg : subarray) {

     
if (msg.type() == type::k_document) {
        document
::view subdoc{msg.get_document()};
       
if (subdoc["uid"] && subdoc["uid"].type() == type::k_int64) {
          std
::cout << "uid: " << subdoc["uid"].get_int64().value << std::endl;
       
}
       
if (subdoc["status"] && subdoc["status"].type() == type::k_int32) {
          std
::cout << "status: " << subdoc["status"].get_int32().value << std::endl;
       
}
       
if (subdoc["uniqueid"] && subdoc["uniqueid"].type() == type::k_utf8) {
          std
::cout << "uniqueid: " << subdoc["uniqueid"].get_utf8().value << std::endl;
       
}
     
} else {
        std
::cout << "Message is not a document" << std::endl;

     
}
   
}
 
} else {
    std
::cout << "Missing or invalid messagelist." << std::endl;
 
}
}


Is that what you were looking for?

Regards,
David

Michael Lin

unread,
Jul 28, 2016, 3:22:56 AM7/28/16
to mongodb-user
Hi David,

It's exactly what I am looking for.

Thank you so much

Best,
Michael
Reply all
Reply to author
Forward
0 new messages