C++11 driver: Placeholder queries / array length

23 views
Skip to first unread message

Per Wohlland

unread,
May 22, 2017, 8:41:01 PM5/22/17
to mongodb-user

Dear people in this group,

unfortunately, I haven't been able to find a way to query the database appropriately. Consider the following document objects:

{
     
"type" : "a",
     
"objects_with_values" : [
         
{    "object_id" : 0x00,
             
"object_type" : "A",
             
"object_values" : [ 0, 1, 2 ]
         
},
         
{    "object_id" : 0x01,
             
"object_type" : "B",
             
"object_values" : [ 3, 4, 6 ]
         
}
     
]
 
}

 

{
     
"type" : "b",
     
"objects_with_values" : [
         
{    "object_id" : 0x03,
             
"object_type" : "A",
             
"object_values" : [ 7, 8, 9 ]
         
},
         
{    "object_id" : 0x04,
             
"object_type" : "B",
             
"object_values" : [ 5, 10, 11 ]
         
}
     
]
 
}



I have two questions:


a) Is it possible to query via placeholders, e.g. 

  

collection.find(document{} << "objects_with_values.$.object_type" << "A" << finalize);


If not, what would be the preferred way to find all object_values of type ==and object_type == A?


b) How can I determine the length of an array, when for some reason all I got is an element instead of view, e.g.


auto r{collection.find(document{} << "type" << "a" << finalize)};
auto elem{r["object_with_values"]};
// ... determine length of elem

Every help is much appreciated! Thanks all!

Sam Rossi

unread,
May 25, 2017, 2:09:13 PM5/25/17
to mongodb-user
Hi Per! For the first question, you'll need to use aggregation to make the query that you describe. If you're not familiar with MongoDB's aggregation framework, you can read about it here. The pipeline that you'll need will look something like this:

[
    {
        "$unwind" : "$objects_with_values",             // Separate each document into one document for each element in the array in the given field
    },
    {
        "$match" : {
            "objects_with_values.object_type" : "A",    // Select only the documents with the field matching a certain value
        }
    },
    {
        "$replaceRoot" : {
            "newRoot" : "$objects_with_values",         // Replace each document with the specified subdocument
        }
    }
])


To use aggregation in mongocxx, use the method collection::aggregate, which takes a pipeline argument.

For your second question, it's important to note that you get back a cursor from a query, which iterates over views to bson documents. For each of these documents, you can get a field using array index notation and then get a view to an array with element::get_array. Finally, you can use std::distance to get the length of the array (not array::view::length, since that returns the number of bytes in the BSON representation of the array). 

When you put it all together, it will look something like this (omitting the exact aggregation query for brevity):

for (auto&& document : collection.aggregate(...)) {
    auto object_values = document[object_values].get_array();

    std::cout << "length of array: " << std::distance(object_values.begin(), object_values.end()) << std::endl;
}

// Prints out "3{newline}3{newline}", since the two subdocuments in the example you gave both have 3 elements in their respective "object_values" subarrays. 

I hope this helps! Let me know if you have any other questions.
Reply all
Reply to author
Forward
0 new messages