Exportando dados filtrados em mais de uma collection

Imagine a seguinte situação:

A equipe estratégica da montadora deseja criar um relatório contendo todas as vendas feitas no mês de agosto de 2020 tanto pela concessionária quanto direto pela fábrica.
O sistema da montadora divide essas vendas em duas collections do mongo.
O relatório é gerado por uma ferramenta consolidada de mercado que aceita a importação dos dados por arquivos .csv ou .json

A primeira solução que vem à cabeça é utilizar o mongoexport com o parâmetro --query para gerar os dados solicitados. No entanto, o mongoexport possui a limitação de só exportar dados de uma única collection por vez.
Fazendo um teste simples de exportar todos os dados de um database sem definir uma collection com o mongoexport obtemos o seguinte resultado:

#$> mongoexport mongodb://localhost:27017 --db examples #comando executado
2021-08-26T08:39:03.607-0300    must specify a collection
2021-08-26T08:39:03.615-0300    try 'mongoexport --help' for more information

Usando o mongosh

O mongosh é a ferramenta básica para interagir com qualquer mongodb. Utilizando ele é possível criar consultas, procedures, indexes e gerenciar o database de maneira geral. Outro ponto interessante é que possível importar scripts .js e executá-los dentro do mongosh. É possível importar o arquivo de duas formas:

  1. Importar diretamente dentro do mongosh
mongosh mongodb://localhost:27017
> load('export_data_multiple_databases/obter_vendas.js')
  1. Importar no momento da execução do mongosh
mongosh mongodb://localhost:27017/examples ~/export_data_multiple_databases/obter_vendas.js

No primeiro caso os resultados gerados são mostrados diretamente no console do mongosh (contexto do mongosh), tornando a tarefa exportar os dados complexa para o cenário apresentado.

Exemplo de execução

Current Mongosh Log ID: 612918a2e3f888785924e0e9
Connecting to:          mongodb://localhost:27017/examples?directConnection=true&serverSelectionTimeoutMS=2000
Using MongoDB:          5.0.0
Using Mongosh Beta:     0.14.0

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting:
   2021-08-27T10:16:56.220+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2021-08-27T10:16:56.525+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2021-08-27T10:16:56.526+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
------
> load('~/export_data_multiple_databases/obter_vendas.js')
[{
  fabricante: 'Lexus',
  modelo: 'LS',
  ano: 2004,
  datavenda: ISODate("2021-08-03T00:00:00.000Z"),
  preco: '$106375.36',
  collectionName: 'vendas_concessionaria'
},
{
  fabricante: 'GMC',
...

Já no segundo caso é possível exportar diretamente para um arquivo externo, pois o comando devolve o resultado no contexto do console e não no contexto do mongosh.

Importante ressaltar que o script importado fica disponível somente naquela sessão.

Exportando para um arquivo

A forma mais simples de exportar para um arquivo é justamente usando o segundo comando de importação de scripts.

mongosh mongodb://localhost:27017/examples ~/export_data_multiple_databases/obter_vendas.js > arquivo_resultado.json

Mongosh --eval

O parâmetro --eval executa um script js inline usando o contexto do mongosh, porém sem carregar o ambiente do mongosh no console. O resultado é da execução é enviado para o console conforme exemplo abaixo:

mongosh mongodb://localhost:27017/examples --eval="load('export_data_multiple_databases/obter_massa_dados.js');"

Como resultado é enviado diretamente para o console (fora do contexto do mongosh), exportar os dados para um arquivo .json é simples

mongosh mongodb://localhost:27017/examples --eval="load('export_data_multiple_databases/obter_massa_dados.js');" > arquivo_resultado.json

A vantagem em relação à exportação padrão é que com o --eval é possível adicionar outras instruções além do que está no script.

Eliminando o cabeçalho com o parâmetro --quiet

Examinando o arquivo exportado, nota-se que os cabeçalhos de inicialização do mongosh também foram exportados.

Current Mongosh Log ID: 6129153e30afffaa9fb76fe4
Connecting to:      mongodb://localhost:27017/examples?directConnection=true&serverSelectionTimeoutMS=2000
Using MongoDB:      5.0.0
Using Mongosh Beta: 0.14.0

For mongosh info see: [1mhttps://docs.mongodb.com/mongodb-shell/]

-----------
   The server generated these startup warnings when booting:
   2021-08-27T10:16:56.220+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2021-08-27T10:16:56.525+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2021-08-27T10:16:56.526+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
-----------

Loading file: ~\export_data_multiple_databases\obter_vendas.js
[{
  fabricante: 'Hyundai',
  modelo: 'Genesis',
  ano: 2009,
...

Para resolver este problema basta adicionar o parâmetro --quiet ao comando de exportação.

Através do método de importação pela linha de comando:

mongosh mongodb://localhost:27017/examples --quiet ~/export_data_multiple_databases/obter_massa_dados.js > arquivo_resultado.json

Usando o --eval:

mongosh mongodb://localhost:27017/examples --quiet --eval="load('export_data_multiple_databases/obter_massa_dados.js');" > arquivo_resultado.json

Ao examinar novamente o arquivo, nota-se que o cabeçalho sumiu e com isso temos um arquivo .json válido e somente com os dados solicitados.

Impressões e Conclusão

A ideia deste post surgiu de uma tarefa que solicitava a exportação de dados oriundos de um schema específico para csv. Tal schema existia em diversas collections com documentos que possuiam campos diferentes entre si. O único ponto em comum dessas collections era justamente um subdocumento com o schema em questão.
Como não sou um profundo conhecedor de mongodb e não encontrei uma forma fácil na documentação e muito menos no stackoverflow e afins, resolvi ser criativo. Me vali da capacidade do mongodb de executar scripts .js e de conhecimentos básicos de shell.

A solução é um tanto verbosa, porém resolveu meu problema de forma simples e eficiente. Imagino que os especialistas em mongodb vão me contar nos comentários:
- basta rodar essa linha de comando que você obtém o mesmo resultado
Mas até lá, vou seguir usando a mesma abordagem para obter esses dados sempre que forem solicitados.

No github (pasta export_data_multiple_databases) deixei o passo a passo de como reproduzir esse post.

Quero deixar um agradecimento especial para o Caio Lucena pelas revisões dos posts publicados até agora.

Referências

16