Menu Docs

Página inicial do DocsDriver C++

Trabalhando com BSON

Nesta página

  • Construtores de documentos
  • Construtor de listas
  • Funções do construtor "único"
  • Construtor básico
  • Construindo arrays em loops
  • Possuir documentos BSON
  • documento BSON que não possuem (visualizações)
  • documento BSON de propriedade opcional (view_or_value)
  • Vida útil do documento BSON
  • Imprimindo documentos BSON
  • Tirando campos 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 um. Para obter mais informações e códigos de exemplo, consulte nossos exemplos .

  1. Construtores de documentos

  2. Possuir documentos BSON (valores)

  3. documento BSON que não possuem (visualizações)

  4. BSON documento de propriedade opcional (view_or_value)

  5. Vida útil do documento BSON

  6. Imprimindo documentos BSON

  7. Tirando campos de documentos BSON

  8. Tipos de JSON

A biblioteca bsoncxx oferece quatro interfaces para construir BSON: funções únicas, um construtor básico, um construtor de lista e um construtor baseado em fluxo.

bsoncxx::builder::base::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, e a escolha de qual usar é totalmente estetica.

A maneira mais simples de criar um documento ou array BSON é usar o construtor de lista semelhante ao 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 esse estado ser alterado, 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 desconcertantes, o uso do construtor de fluxos não é recomendado. Recomendamos, em vez disso, usar o construtor básico ou as funções únicas do construtor.

Às vezes, é necessário construir uma array usando 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 uma 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 criar uma array com o construtor de stream, é importante estar ciente de que o tipo de retorno ao usar o operador << em um construtor de stream não é uniforme. Para construir uma matriz em um loop corretamente, os valores intermediários retornados pelo construtor de fluxo devem ser armazenados em variáveis quando o tipo muda. Uma tentativa de construir uma matriz a partir de um construtor de fluxo 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ê quiser fazer a divisão da única declaração dentro do loop for acima em várias declarações, deverá 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, 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 utilizando a interface do construtor de stream e o token finalize . finalize retorna um document::value de um construtor de fluxo temporário:

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

bsoncxx::document::visualizar

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 é convertido 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 porque podemos evitar cópias em excesso. Além disso, passar uma 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 r, portanto, a propriedade do documento será 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 tipos view_or_value diretamente para usar o driver. Eles são oferecidos como um método de conveniência para permitir que os métodos do driver levem documentos de forma própria ou não. 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 retorna uma visualizaçã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!!
}

Esse 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 a partir 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 facilitar a 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 construir document::values a partir de strings JSON existentes.

O operador [ ] entra em 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 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_} 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.

←  Pool de ConexõesVersão de API e ABI →