Redirecione a saída da consulta mongo para um arquivo csv

88

Estou usando o MongoDB 2.2.2 para máquina Windows7 de 32 bits. Eu tenho uma consulta de agregação complexa em um arquivo .js. Preciso executar este arquivo no shell e direcionar a saída para um arquivo CSV. Asseguro-me de que a consulta retorne um json "simples" (sem chaves aninhadas), portanto, é inerentemente conversível em um csv puro.

Eu sei sobre load()e eval(). eval()requer que eu cole toda a consulta no shell e permite apenas printjson()dentro do script, enquanto eu preciso do csv. E, a segunda forma: load()..Imprime a saída na tela, e novamente no formato json.

Existe uma maneira de o Mongo fazer essa conversão de json para csv? (Eu preciso do arquivo csv para preparar gráficos sobre os dados). Estou pensando:

1. Ou o mongo tem um comando integrado para isso que não consigo encontrar no momento.
2. Mongo não pode fazer isso por mim; Posso no máximo enviar a saída json para um arquivo que eu mesmo preciso converter para csv.
3. O Mongo pode enviar a saída json para uma coleção temporária, cujo conteúdo pode ser facilmente mongoexportedpara o formato csv. Mas acho que apenas as consultas de redução de mapa suportam coleções de saída. Isso está certo? Eu preciso disso para uma consulta de agregação.

Obrigado por qualquer ajuda :)

Aafreen Sheikh
fonte
1
Se isso é algo que você faz com frequência, considere escrever um EXE autônomo usando .NET, python ou NodeJs; cada um tem um driver nativo que tornaria mais fácil executar seu código e produzir a saída desejada.
WiredPrairie
Refiro-me à resposta de Zachary em stackoverflow.com/questions/4130849/… e sou capaz de converter de json para csv. Mas, como alternativa, posso enviar o json para uma coleção e, em seguida, fazer uma exportação mongo?
Aafreen Sheikh
Eu recomendo que você apenas construa um pequeno chicote usando Node e o driver MongoDB para NodeJS e então você pode executar qualquer código que desejar. Você obteria os resultados desejados muito rapidamente, sem a necessidade do shell. Seria muito fácil de manter (e depurável).
WiredPrairie

Respostas:

179

Sei que esta pergunta é antiga, mas passei uma hora tentando exportar uma consulta complexa para csv e queria compartilhar minhas ideias. Primeiro, não consegui fazer nenhum dos conversores json para csv funcionarem (embora este parecesse promissor). O que acabei fazendo foi escrever manualmente o arquivo csv no meu script mongo.

Esta é uma versão simples, mas essencialmente o que eu fiz:

print("name,id,email");
db.User.find().forEach(function(user){
  print(user.name+","+user._id.valueOf()+","+user.email);
});

Acabei de canalizar a consulta para stdout

mongo test export.js > out.csv

onde testestá o nome do banco de dados que uso.

GEverding
fonte
Como eu especificaria em qual banco de dados a coleção de usuário está?
Nelu
2
@NeluMalancea verifique os documentos do MongoDB, eles têm essas informações. Você pode especificar o banco de dados adicionando use <database>ao início do script
GEverding
2
Na verdade, como os auxiliares de shell, como "use <database>" não são javascript, eles não são permitidos. Consulte docs.mongodb.org/manual/tutorial/… . Em vez disso, inicie seu script mais ou menos assim: conn = new Mongo (); db = conn.getDB ('your_db_name');
Steve Hansen Smythe
2
@NeluMalancea o comando mongo aceita um url db (e usuário, passa, ...)
iwein
3
@NeluMalancea o testno último comando é o nome do banco de dados, apenas substitua pelo nome do seu banco de dados.
Zoltán
116

A exportação embutida do Mongo está funcionando bem, a menos que você queira qualquer manipulação de dados, como formato de data, tipos de dados ocultos, etc.

Seguir o comando funciona como um encanto.

    mongoexport -h localhost -d databse -c collection --type=csv 
    --fields erpNum,orderId,time,status 
    -q '{"time":{"$gt":1438275600000}, "status":{"$ne" :"Cancelled"}}' 
    --out report.csv
Thisarattr
fonte
17
Muito obrigado! Dica: agora é em --type=csvvez de --csv.
janeiro de
A limitação do mongoexport é que você não pode manipular os campos. O mongo id é exportado como ObjectId (mongidstring). Ser capaz de exportar os resultados de um script de shell mongo é melhor se alguém quiser manipular os dados dos campos (por exemplo ObjectId (mongidstring) .toString ()).
Raj006
1
posso fazer operações de agregação?
Hendy Irawan
Essa solução funcionou. Mas para o Windows eu tive que fazer duas alterações: eu só precisava de apóstrofo duplo de fora e apóstrofos simples de dentro como este -q "{nome: 'stackoverflow'}", também para porta que especifica o comando -p não funcionou, eu usei - -port 27000.
nurb
10

Estendendo outras respostas:

Achei a resposta de @ GEverding mais flexível. Também funciona com agregação:

test_db.js

print("name,email");

db.users.aggregate([
    { $match: {} }
]).forEach(function(user) {
        print(user.name+","+user.email);
    }
});

Execute o seguinte comando para exportar os resultados:

mongo test_db < ./test_db.js >> ./test_db.csv

Infelizmente, ele adiciona texto adicional ao arquivo CSV, o que requer o processamento do arquivo antes de podermos usá-lo:

MongoDB shell version: 3.2.10 
connecting to: test_db

Mas podemos fazer o shell mongo parar de cuspir esses comentários e apenas imprimir o que pedimos passando a --quietbandeira

mongo --quiet test_db < ./test_db.js >> ./test_db.csv
Lucky Soni
fonte
1
Editar sua resposta seria melhor do que adicionar uma nova.
Renato Voltar
6

Aqui está o que você pode tentar:

print("id,name,startDate")
cursor = db.<collection_name>.find();
while (cursor.hasNext()) {
    jsonObject = cursor.next();
    print(jsonObject._id.valueOf() + "," + jsonObject.name + ",\"" + jsonObject.stateDate.toUTCString() +"\"")

}

Salve em um arquivo, diga "export.js". Execute o seguinte comando:

mongo <host>/<dbname> -u <username> -p <password> export.js > out.csv
Shirish Kumar
fonte
5

Dê uma olhada nisso

para a saída do shell mongo para o arquivo. Não há suporte para a saída de csv do shell mongos. Você teria que escrever o javascript sozinho ou usar um dos muitos conversores disponíveis. Google "converter json para csv", por exemplo.

geakie
fonte
1

Só estou pensando aqui com uma boa solução que tenho usado. Isso é semelhante à solução de Lucky Soni acima, pois oferece suporte à agregação, mas não requer codificação permanente dos nomes dos campos.

cursor = db.<collection_name>.<my_query_with_aggregation>;

headerPrinted = false;
while (cursor.hasNext()) {
    item = cursor.next();
    
    if (!headerPrinted) {
        print(Object.keys(item).join(','));
        headerPrinted = true;
    }

    line = Object
        .keys(item)
        .map(function(prop) {
            return '"' + item[prop] + '"';
        })
        .join(',');
    print(line);
}

Salve isso como um .jsarquivo, neste caso, vamos chamá-lo example.jse executá-lo com a linha de comando mongo assim:

mongo <database_name> example.js --quiet > example.csv
TimmyGee
fonte
0

Eu uso a seguinte técnica. Isso torna mais fácil manter os nomes das colunas sincronizados com o conteúdo:

var cursor = db.getCollection('Employees.Details').find({})

var header = []
var rows = []

var firstRow = true
cursor.forEach((doc) => 
{
    var cells = []
    
    if (firstRow) header.push("employee_number")
    cells.push(doc.EmpNum.valueOf())

    if (firstRow) header.push("name")
    cells.push(doc.FullName.valueOf())    

    if (firstRow) header.push("dob")
    cells.push(doc.DateOfBirth.valueOf())   
    
    row = cells.join(',')
    rows.push(row)    

    firstRow =  false
})

print(header.join(','))
print(rows.join('\n'))
Fidel
fonte
0

Ao executar um script em um servidor remoto. O Mongo adicionará sua própria saída de registro, que podemos querer omitir de nosso arquivo. --quietopção irá apenas desativar os logs relacionados à conexão. Nem todos os logs do mongo. Nesse caso, talvez seja necessário filtrar as linhas desnecessárias manualmente. Um exemplo baseado em Windows:

mongo dbname --username userName --password password --host replicaset/ip:port --quiet printDataToCsv.js | findstr /v "NETWORK" > data.csv

Isso canalizará a saída do script e usará findstrpara filtrar quaisquer linhas que contenham a string NETWORK. Mais informações sobre findstr: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr

Uma versão Linux disso usaria grep.

Simon Katanski
fonte