Para agentes de IA: um índice de documentação está disponível em https://www.mongodb.com/pt-br/docs/llms.txt — as versões de markdown de todas as páginas estão disponíveis anexando .md a qualquer caminho de URL.
Menu Docs

Trabalhando com BSON

O driver mongocxx é fornecido com uma nova biblioteca, bsoncxx. Este artigo abordará alguns dos diferentes tipos nesta biblioteca e como e quando usar cada uma. Para obter mais informações e código de exemplo, consulte nossos exemplos.

A biblioteca bsoncxx oferece quatro interfaces para a criação de BSON: funções pontuais, um construtor básico, um construtor de lista e um construtor baseado em fluxo.

bsoncxx::builder::basic::document bsoncxx::builder::stream::document

Os vários métodos de criação de documentos e arrays BSON são todos equivalentes. Todas as interfaces fornecerão os mesmos resultados, a escolha de qual usar é inteiramente estetica.

A maneira mais simples de criar um documento BSON ou array é usar o construtor de lista semelhante a JSON:

// { "hello": "world" }
bsoncxx::builder::list list_builder = {"hello", "world"};
bsoncxx::document::view document = list_builder.view().get_document();

Usos mais avançados do construtor de listas são mostrados em neste exemplo.

O construtor "One-off" cria documentos e arrays em uma única chamada. Eles podem ser usados quando nenhuma lógica adicional (como condicionais ou loops) precisa ser usada para criar o objeto:

using bsoncxx::builder::basic::kvp;
// { "hello": "world" }
bsoncxx::document::value document = bsoncxx::builder::basic::make_document(kvp("hello", "world"));
using bsoncxx::builder::basic::kvp;
// { "hello" : "world" }
bsoncxx::builder::basic::document basic_builder{};
basic_builder.append(kvp("hello", "world"));
bsoncxx::document::value document = basic_builder.extract();

Usos mais avançados do construtor básico são mostrados em neste exemplo.

// { "hello" : "world" }
using bsoncxx::builder::stream;
bsoncxx::document::value document = stream::document{} << "hello" << "world" << stream::finalize;

Usos mais avançados do construtor de stream são mostrados em neste exemplo.

Observação

Para anexar adequadamente cada novo valor, um construtor de fluxo precisa acompanhar o estado do documento atual, incluindo o nível de aninhamento e o tipo do valor mais recente anexado ao construtor. O construtor de fluxo inicial não deve ser reutilizado após essas alterações de estado, o que significa que os valores intermediários devem ser armazenados em novas variáveis se um documento estiver sendo criado com o construtor de fluxo em várias instruções. Como fazer isso corretamente é difícil e as mensagens de erro do compilador podem ser confusas, o uso do construtor de stream é desaconselhado. Recomendamos, em vez disso, usar o construtor básico ou as funções únicas do construtor.

Às vezes é necessário construir uma array utilizando um loop. Com o construtor básico, uma array de nível superior pode ser criada simplesmente chamando append dentro de um loop:

// [ 1, 2, 3 ]
const auto elements = {1, 2, 3};
auto array_builder = bsoncxx::builder::basic::array{};
for (const auto& element : elements) {
array_builder.append(element);
}

Para construir uma sub-array em um loop, passe um Lambda para append (ou como o segundo argumento de kvp se a sub-array estiver contida por um documento em vez de um array):

// { "foo" : [ 1, 2, 3 ] }
using bsoncxx::builder::basic::kvp;
using bsoncxx::builder::basic::sub_array;
const auto elements = {1, 2, 3};
auto doc = bsoncxx::builder::basic::document{};
doc.append(kvp("foo", [&elements](sub_array child) {
for (const auto& element : elements) {
child.append(element);
}
}));

Ao construir uma array com o construtor de stream, é importante estar ciente de que o tipo de retorno de utilizar o operador << em um construtor de stream não é uniforme. Para construir uma array em um loop corretamente, os valores intermediários retornados pelo construtor de stream devem ser armazenados em variáveis quando o tipo for alterado. Uma tentativa de construir uma array a partir de um construtor de stream usando um loop pode ter a seguinte aparência:

// { "subdocs" : [ { "key" : 1 }, { "key" : 2 }, { "key" : 3 } ], "another_key" : 42 }
using namespace bsoncxx;
builder::stream::document builder{};
auto in_array = builder << "subdocs" << builder::stream::open_array;
for (auto&& e : {1, 2, 3}) {
in_array = in_array << builder::stream::open_document << "key" << e
<< builder::stream::close_document;
}
auto after_array = in_array << builder::stream::close_array;
after_array << "another_key" << 42;
document::value doc = after_array << builder::stream::finalize;
std::cout << to_json(doc) << std::endl;

Observação

O resultado de qualquer operação de fluxo deve ser capturado, portanto, se você deseja dividir a única declaração dentro do loop for acima em várias declarações, você deve capturar cada resultado intermediário. Além disso, a última declaração dentro do corpo do loop deve atribuir seu resultado de volta ao objeto in_array, para que o loop seja reiniciado em um estado consistente:

for (auto && e : {1, 2, 3}) {
auto open_state = in_array << builder::stream::open_document;
auto temp_state = open_state << "key" << e;
in_array = temp_state << builder::stream::close_document;
}

bsoncxx::document::value

Esse tipo representa um documento BSON real, um que possui seu buffer de dados. Esses documentos podem ser construídos a partir de um construtor ligando para extract():

bsoncxx::document::value basic_doc{basic_builder.extract()};
bsoncxx::document::value stream_doc{stream_builder.extract()};

Depois de chamar extract() , o construtor está em um estado movido de e não deve ser usado.

É possível criar um bsoncxx::document::value em uma única linha usando a interface do construtor de fluxo e o token finalize . finalize retorna um document::value de um construtor de stream temporário:

// { "finalize" : "is nifty" }
bsoncxx::document::value one_line = bsoncxx::builder::stream::document{} << "finalize" << "is nifty" << bsoncxx::builder::stream::finalize;

bsoncxx::document::view

Este tipo é uma visualização de um bsoncxx::document::value proprietário .

bsoncxx::document::view document_view{document_value.view()};

Um document::value também se converte implicitamente em um document::view:

bsoncxx::document::view document_view{document_value};

Em códigos críticos de desempenho, é preferível passar visualizações do que usar valores, pois podemos evitar cópias em excesso. Além disso, passar a visualização de um documento nos permite usá-lo várias vezes:

// { "copies" : { "$gt" : 100 } }
auto query_value = document{} << "copies" << open_document << "$gt" << 100 << close_document << finalize;
// Run the same query across different collections
auto collection1 = db["science_fiction"];
auto cursor1 = collection1.find(query_value.view());
auto collection2 = db["cookbooks"];
auto cursor2 = collection2.find(query_value.view());

Muitos métodos de driver usam um parâmetro document::view_or_value, por exemplo, run_command:

bsoncxx::document::value run_command(bsoncxx::document::view_or_value command);

Esses métodos podem levar um document::view ou um document::value. Se um document::value for passado, ele deverá ser passado por referência de valor de r, para que a propriedade do documento seja transferida para o método.

document::value ping = document{} << "ping" << 1 << finalize;
// You can pass a document::view into run_command()
db.run_command(ping.view());
// Or you can move in a document::value
db.run_command(std::move(ping));

Você não precisa criar view_or_value tipos diretamente para usar o driver. Eles são oferecidos como um método de conveniência para permitir que os métodos de driver levem documentos de forma proprietário ou não proprietário. O tipo view_or_value também ajuda a mitigar alguns dos problemas de vida útil discutidos na próxima seção.

É obrigatório que os tipos document::value sobrevivam a quaisquer tipos document::view que os utilizem. Se o valor subjacente for limpo, a visualização ficará com um ponteiro pendente. Considere um método que retorne uma exibição de um documento recém-criado:

bsoncxx::document::view make_a_dangling_view() {
bsoncxx::builder::basic::document builder{};
builder.append(kvp("hello", "world"));
// This creates a document::value on the stack that will disappear when we return.
bsoncxx::document::value stack_value{builder.extract()};
// We're returning a view of the local value
return stack_value.view(); // Bad!!
}

Este método retorna uma visualização pendente que não deve ser usada:

// This view contains a dangling pointer
bsoncxx::document::view dangling_view = make_a_dangling_view(); // Warning!!

A tentativa de criar uma visualização fora de um construtor criará da mesma forma um objeto de visualização perigoso, porque o valor temporário retornado de extract() não é capturado:

bsoncxx::builder::stream::document temp_builder{};
temp_builder << "oh" << "no";
bsoncxx::document::view dangling_view = temp_builder.extract().view(); // Bad!!

bsoncxx::to_json()

A biblioteca bsoncxx vem com um método de conveniência para converter documentos BSON em strings para fácil inspeção:

bsoncxx::document::value = document{} << "I am" << "a BSON document" << finalize;
std::cout << bsoncxx::to_json(doc.view()) << std::endl;

Existe um método análogo, from_json(), para criar documento::valores a partir de strings JSON existentes.

Aviso

Valide entradas não confiáveis antes de converter JSON em BSON

Se você converter uma string JSON para BSON e usar o BSON resultante em uma query, atualizar ou comando, um invasor pode injetar operadores ou valores de campo inesperados que alteram o significado da operação. Esse risco é maior quando o JSON se origina de um usuário, uma solicitação de API ou outra fonte não confiável.

To learn more about validating input before conversion, see Validate Untrusted Input Before Converting JSON to BSON.

O operador [ ] acessa um documento BSON para recuperar valores:

// doc_view = { "store" : "Key Foods", "fruits" : [ "apple", "banana" ] }
auto store = doc_view["store"];
auto first_fruit = doc_view["fruits"][0];

Isso retorna um bsoncxx::document::element, que contém o valor real desejado:

document::element store_ele{doc_view["store"]};
if (store_ele) {
// this block will only execute if "store" was found in the document
std::cout << "Examining inventory at " << to_json(store_ele.get_value()) << std::endl;
}

Esta funcionalidade é mostrada com mais detalhes em neste exemplo e neste exemplo.

A especificação BSON fornece uma lista de tipos suportados. Eles são representados em C++ usando os wrappers do tipo b_XXX.

Alguns BSON types não têm necessariamente uma representação nativa para envolver e são implementados por meio de classes especiais.

A classe bsoncxx::decimal128 representa um valor decimal de ponto flutuante 128-bit IEEE 754-2008 . Esperemos que os usuários os convertam de e para strings, mas fornecemos acesso aos valores mínimo e máximo 64bits se os usuários precisarem converter para um tipo decimal nativo128 .

Você pode ver como trabalhar com bsoncxx::decimal128 em neste exemplo.