как извлечь поля из потока изменений mon go db с помощью C libbson - PullRequest
0 голосов
/ 27 мая 2020

У меня есть bson_t «b» из потока изменений mon go db, который напечатан следующим образом bson_as_canonical_extended_ json:

{ "_id" : { "_data" : "825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F
03E803FB80F1F463C5F6964003C3030313330323637000004" },   
"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" : [  ] } }  

Я могу перейти к таким полям «documentKey» :

bson_iter_t iter;
if (bson_iter_init_find(&iter, b, "documentKey"))
bson_iter_t child;
if (bson_iter_recurse(&iter, &child))
{
    while (bson_iter_next(&child))
    {
        const bson_value_t *value = bson_iter_value(&child);
        printf("documentKey sub-key %s value %s\n", bson_iter_key(&child), (char*)value->value.v_utf8.str);
    }
}

который печатает "_id": "00130267"
как получить доступ к полям "updateDescription", есть ли где-нибудь примеры
эта структура не является моей mon go db change stream

более поздний ответ Баумана более строгий, для меня это работает:

bson_iter_t iter1;
if (bson_iter_init_find(&iter1, b, "updateDescription")) // doc 
{
    bson_iter_t child1;
    if (bson_iter_recurse(&iter1, &child1))
    {
        while (bson_iter_next(&child1))// updatedFields doc
        {
            bson_iter_t child2;
            bson_iter_recurse(&child1, &child2);
            while (bson_iter_next(&child2))
            {
                const bson_value_t *value = bson_iter_value(&child2);
                printf("updateDescription arr %s value %s\n", bson_iter_key(&child2), (char*)value->value.v_utf8.str);// key and value of the array
            }
        }
    }
}

1 Ответ

0 голосов
/ 28 мая 2020

Вам нужно будет спуститься дважды, сначала во внешний документ, а затем во внутренний.

Документация 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.

...