#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. Но вы можете это сделать.