как добавить поля в bson в драйвере MongoDB C

#mongodb #bson

Вопрос:

Для добавления к массовой записи, чтобы обновить существующие поля в документе, я не могу сделать все это на месте, мне нужно повторно вызывать функцию добавления по мере поступления данных, спасибо за любые подсказки, я не знаю, как это сделать?

 void appendfn(bson_t* doc, char * name, char* value) 
{
    char *str;
    bson_t child;

    bson_append_document_begin (doc, "$set", -1, amp;child);
    BSON_APPEND_UTF8(amp;child, name, value);
    bson_append_document_end (doc, amp;child);

    str=bson_as_canonical_extended_json (doc, NULL);
    printf("%sn",str);
}
 

bson_t doc=BSON_INITIALIZER;
appendfn(amp;doc,»f1″,»f1v») выдает :
{ «$set»: { «f1»: «f1v» } }

если я снова вызову его appendfn(amp;doc,»f2″, «f2v») :

{ «$set»: { «f1»: «f1v» }, «$set»: { «f2»: «f2v» } }

но мне нужно :

{ «$set»: { «f1»: «f1v», «f2»: «f2v» } }

ради аргумента я мог бы сделать что-то в этом роде (из одного потока) :

     void appendmore(bson_t* doc, char * name, char* value) 
    {
        char *str;
        static bson_t *child=NULL;// static is only for single thread obviously, need thread local storage for multiple threads
    
        if(!child)
        {
            child=bson_new ();
            bson_append_document_begin (doc, "$set", -1, child);
        }
        if(name)
        {
            BSON_APPEND_UTF8(child, name, value);
            str=bson_as_canonical_extended_json (child, NULL);
            printf("child %sn",str);
        }
        else
            bson_append_document_end (doc, child);
    }

appendmore(amp;doc,"f1","f1v");
appendmore(amp;doc,"f2","f2v");
appendmore(amp;doc,NULL,NULL);
 

должен быть способ продолжить добавление полей в «открытый» дочерний элемент? т.Е. каким-то образом повторно открыть его?

еще одна вещь, которую я не могу понять, с последним драйвером 1.19 c дочерний элемент, похоже, не может быть выделен с помощью new, он должен быть статическим, потому что он помечается как BSON_FLAG_NO_FREE

чтобы лучше сформулировать вопрос с точки зрения оригинальной документации BSON: http://mongoc.org/libmongoc/1.17.6/tutorial.html

имя: { сначала: «Grace», последнее: «Hopper» },

как продолжить добавление полей в документе «имя», скажем, с несколькими bson_append_document_begin ? как указать добавление к существующему ключу «name», это может быть обозначение «точка», но как с точки зрения библиотеки mongo C?

Ответ №1:

Я думаю, проблема сводится к попытке добавить новые child документы во внешний doc .

должен быть способ продолжить добавление полей в «открытый» дочерний элемент

Да, добавьте ключ / значения к child , а не открывайте новые дочерние элементы bson_t на главном doc

Удерживайте ссылку на child и добавляйте к ней все, что хотите

Как только у вас есть child , просто добавьте свой utf8 (или любой другой) ключ / значения к child , а не продолжайте открывать новый child ren на doc .

Как только вы закончите добавление child , только тогда вы сможете вызвать bson_append_document_end child

 
static
void append_more(bson_t * child, const char * key, const char * value){
    // This doesn't really need to be a function, but to match the example
    if (key) {
        BSON_APPEND_UTF8(child, key, value);
    }
}

static
void appending_test(){
    bson_t doc=BSON_INITIALIZER;
    bson_t child;
    // prepare the child outside of the append function
    bson_append_document_begin (amp;doc, "$set", -1, amp;child);


    // Example appended UTF8 to the outer doc, rather than to the child
    BSON_APPEND_UTF8(amp;child, "k1", "v1");  // Append directly
    // Or wrap the call in a function
    append_more(amp;child, "k2", "v2"); //append_more created above
    append_more(amp;child, "k3", "v3"); //append_more created above

    // don't call this until you're done appending
    bson_append_document_end(amp;doc, amp;child);

    printf("%sn", bson_as_canonical_extended_json(amp;doc, NULL));
}

 

С принтами

     { "$set" : { "k1" : "v1", "k2" : "v2", "k3" : "v3" } }
 

Для вашего второго конкретного примера,

 
static
void name_test(){
    bson_t doc=BSON_INITIALIZER;
    bson_t name_field;
    // prepare the child outside of the append function
    bson_append_document_begin (amp;doc, "name", -1, amp;name_field);

    append_more(amp;name_field, "first", "Grace"); //append_more created above
    append_more(amp;name_field, "last", "Hopper"); //append_more created above

    // don't call this until you're done appending
    bson_append_document_end(amp;doc, amp;name_field);

    printf("%sn", bson_as_canonical_extended_json(amp;doc, NULL));
}


 

С принтами

 { "name" : { "first" : "Grace", "last" : "Hopper" } }
 

Наконец, ваш вопрос о bson_new все еще работает в 1.19

Где-то в вашей программе вам нужно использовать bson_new , чтобы поместить ваш документ в кучу. В конце вашей программы используйте bson_destroy для его очистки. Вероятно, вы сталкиваетесь с ошибками, потому что вы bson_new создаете свой child ren, когда не должны

 
static
void heap_test(){
    // Using a bson pointer to heap rather than struct on stack
    bson_t * doc = bson_new();
    bson_t * name_field = bson_new();

    bson_append_document_begin (doc, "name", -1, name_field);
    // -------------------------^ not a reference anymore

    append_more(name_field, "first", "Grace"); //append_more created above
    append_more(name_field, "last", "Hopper"); //append_more created above
    // ---------^ not a reference anymore

    // don't call this until you're done appending
    bson_append_document_end(doc, name_field);
    // ----------------------^ not a reference anymore

    printf("%sn", bson_as_canonical_extended_json(doc, NULL));
    // ---------------------------------------------------^ not a reference anymore


    // Must destroy documents from the heap
    bson_destroy(name_field);
    bson_destroy(doc);
}

 

С принтами

 { "name" : { "first" : "Grace", "last" : "Hopper" } }
 

Переполнение стека по умолчанию использует смехотворно защищенную лицензию для этих ответов. Насколько это возможно, я размещаю весь код и слова в этом ответе в открытом доступе. Там, где общественное достояние не разрешено или не распознано, код и слова лицензируются по той же лицензии, что и сам libbson.

Комментарии:

1. хм, можете ли вы вызвать несколько раз bson_append_document_begin / end для одного и того же родителя? допустим, «Grace» «Хоппер», «Grace1» «Хоппер1», «Grace2» «Хоппер2» …

2. да, это именно то, что вы сделали в вопросе, где вы получили два ключа $set с их собственными данными.

3. хм, насколько я понимаю, вы не можете повторно вставить поддерево в родительское, которое каким-то образом остается «открытым» в каком-то состоянии, не подлежащем повторной установке? Надеюсь, я ошибаюсь? Я думаю, это связано с тем, что это двоичные структуры, и вам нужно «физически» перемещать двоичные фрагменты?

4. хм, также обратите внимание на официальный пример, почему они вставляют поддерево «Grace Hopper» только один раз и только один раз

5. вы спросили, можете ли вы, да, можете. Вы не должны, потому что это приведет к ошибкам синтаксического анализа в дайверах, которые не могут обрабатывать дубликаты ключей в документе BSON. Но вы можете это сделать.