Menu Docs
Página inicial do Docs
/ / /
Driver C++

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 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 .

  1. Construtores de documentos

  2. Possuir documentos BSON (valores)

  3. Documentos BSON não proprietários (visualizações)

  4. Documentos BSON de propriedade opcional(view_or_value)

  5. Vida útil do documento BSON

  6. Imprimindo documentos BSON

  7. Obtendo campos fora de documentos BSON

  8. Tipos de JSON

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 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 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.

À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;
}

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 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.

É 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.

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.

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.

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.

Voltar

Pool de Conexões