Вам нужно будет спуститься дважды, сначала во внешний документ, а затем во внутренний.
Документация libbson действительно хороша. props to the mongodb staff
вот полный пример
#include <bson.h>
void descending_to_updateDescription(bson_t *b){
bson_iter_t change_iter;
if (bson_iter_init_find(&change_iter, b, "updateDescription"))
{
bson_iter_t desired_field;
if (bson_iter_recurse(&change_iter, &desired_field))
{
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value)
// pointer is now here | (at the beginning of the document
// confirm the (value) is type DOCUMENT as we expect (containing keys, "updateFields" and "removedFields"
if BSON_ITER_HOLDS_DOCUMENT(&change_iter){
while (bson_iter_next(&desired_field))
{
// printing the outer key (expect 2, shown below)
printf("%s\n", bson_iter_key(&desired_field));
// first loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) -- another document
// pointer is now here ----------------- |
//
// next loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a list
// pointer is now waaaaaaaaaayyyyyyyy ovvvvvveeeeerrr here --------------------------------------------------- |
// next loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// ^
// pointer is now waaaaaaaaaayyyyyyyy ovvvvvveeeeerrr here ---------------------------------------------------------- | (end of document
// iter_next returns false, because no other keys in the outer dict
// descend into the next level down
bson_iter_t changefields_iter;
// SUPER IMPORTANT, recurese from desired_field, not from the original change iter!
if (bson_iter_recurse(&desired_field, &changefields_iter)){
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a document
// pointer is now here -------------------- |
// expect update fields to hold a documnet, and removeFields to hold a list, skip processing remove fields
while (bson_iter_next(&changefields_iter)) {
// first loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a string in this example
// pointer is now here --------------------------------|
// second loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a string in this example
// pointer is now here --------------------------------------------------------|
// third loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// ^
// pointer is now here ----------------------------------------------------------------------| (end of document)
// Example looks like we expect string values, so check for it
if (BSON_ITER_HOLDS_UTF8(&changefields_iter)){
uint32_t length; // iterating the string object can give you length, we don't need it though because we're not strncopying
printf(
"\tKey: %s \t Value: %s\n",
bson_iter_key(&changefields_iter),
bson_iter_utf8(&changefields_iter, &length)
);
}
}
}
}
}
}
}
}
int main(){
// just setting up
char * json_data = "{ \"_id\" : { \"_data\" : \"825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F03E803FB80F1F463C5F6964003C3030313330323637000004\" }, \"operationType\" : \"update\", \"clusterTime\" : { \"$timestamp\" : { \"t\" : 1590448106, \"i\" : 46 } }, \"ns\" : { \"db\" : \"test\", \"coll\" : \"my_collection\" }, \"documentKey\" : { \"_id\" : \"00130267\" }, \"updateDescription\" : { \"updatedFields\" : { \"0x000F\" : \"25.006001\", \"0x0010\" : \"24.976000\" }, \"removedFields\" : [ ] } }" ;
bson_error_t error;
bson_t *b;
b = bson_new_from_json ((uint8_t*)json_data, -1, &error);
descending_to_updateDescription(b);
bson_destroy(b);
b = NULL; // explicit nulled in case this is extended later
return 0;
}
это результат
updatedFields
Key: 0x000F Value: 25.006001
Key: 0x0010 Value: 24.976000
removedFields
Process finished with exit code 0
Важным фактом является второй спуск.
Когда вы найдете и повторно войдете в updateDescription, вам нужно будет снова спуститься в документы updatedFields / updatedFields, а также go распечатать их.
Кроме того, если вы действительно просто хотите проверить «updateFields» вы всегда можете превратить явное, а l oop в неявное (выполняется библиотека), в то время как l oop используйте точечную нотацию и функцию find_descendant . Ваш код выглядит чище, но вы не экономите производительность, делая это, библиотека делает то же l oop, что и в приведенном выше примере
#include <bson.h>
void descending_direct_to_updateFields(bson_t *b){
bson_iter_t change_iter;
bson_iter_t updateFields_iter;
// use the find_descendant function
if (bson_iter_init(&change_iter, b) && bson_iter_find_descendant(&change_iter, "updateDescription.updatedFields", &updateFields_iter)) {
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - document with 2 keys
// pointer is now here -------------------|
printf("%s\n", "updateDescription.updatedFields"); // just print because you looked for it
if BSON_ITER_HOLDS_DOCUMENT(&updateFields_iter){
bson_iter_t desired_field;
bson_iter_recurse(&updateFields_iter, &desired_field);
while (bson_iter_next(&desired_field)) {
if (BSON_ITER_HOLDS_UTF8(&desired_field)) {
uint32_t length; // iterating the string object can give you length, we don't need it though because we're not strncopying
printf(
"\tKey: %s \t Value: %s\n",
bson_iter_key(&desired_field),
bson_iter_utf8(&desired_field, &length)
);
}
}
}
}
}
int main(){
// just setting up
char * json_data = "{ \"_id\" : { \"_data\" : \"825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F03E803FB80F1F463C5F6964003C3030313330323637000004\" }, \"operationType\" : \"update\", \"clusterTime\" : { \"$timestamp\" : { \"t\" : 1590448106, \"i\" : 46 } }, \"ns\" : { \"db\" : \"test\", \"coll\" : \"my_collection\" }, \"documentKey\" : { \"_id\" : \"00130267\" }, \"updateDescription\" : { \"updatedFields\" : { \"0x000F\" : \"25.006001\", \"0x0010\" : \"24.976000\" }, \"removedFields\" : [ ] } }" ;
bson_error_t error;
bson_t *b;
b = bson_new_from_json ((uint8_t*)json_data, -1, &error);
descending_direct_to_updateFields(b);
bson_destroy(b);
b = NULL; // explicit nulled in case this is extended later
return 0;
}
это результат
updateDescription.updatedFields
Key: 0x000F Value: 25.006001
Key: 0x0010 Value: 24.976000
По умолчанию для этих ответов используется смехотворно избыточная лицензия на переполнение стека. Насколько это разрешено, я помещаю весь код и слова в этом ответе в домен publi c. Там, где домен publi c не разрешен или не распознается, код и слова лицензируются под той же лицензией, что и сам libbson.