Trabalhando com BSON
Nesta página
- Construtores de documentos
- Construtor de listas
- Funções de construtor "one-off"
- Construtor básico
- Construindo arrays em loops
- Possuir documentos BSON
- Documentos BSON não proprietários (visualizações)
- Documentos BSON de propriedade opcional (view_or_value)
- Vida útil do documento BSON
- Imprimindo documentos BSON
- Obtendo campos fora de documentos BSON
- Tipos de JSON
O driver mongocxx é fornecido com uma nova biblioteca, bsoncxx. Este artigo abordará Go alguns dos diferentes tipos nesta biblioteca e como e quando usar cada uma. Para obter mais informações e códigos de exemplo , consulte nossos exemplos do.
Construtores de documentos
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.
Construtor de listas
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 neste exemplo.
Funções de construtor "one-off"
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"));
Construtor básico
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 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 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.
Construindo arrays em loops
Às vezes é necessário construir uma array utilizando um loop. Com o construtor básico, uma array de nível superior pode ser construída 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; }
Possuir documentos BSON
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;
Documentos BSON não proprietários (visualizações)
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());
Documentos BSON de propriedade opcional (view_or_value)
Muitos métodos de driver usam um document::view_or_value
parâmetro , 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.
Vida útil do documento BSON
É 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!!
Imprimindo documentos BSON
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.
Obtendo campos fora de documentos 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; }
Este recurso é mostrado em mais detalhes neste exemplo e este exemplo.
Tipos de JSON
A especificação BSON fornece uma lista de tipos suportados. Eles são representados em C++ usando o b_XXX tipo wrappers.
Alguns BSON types não têm necessariamente uma representação nativa para envolver e são implementados por meio de classes especiais.
Decimal128
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
neste exemplo.