Como executar comandos mongo através de scripts shell?

404

Eu quero executar mongocomandos no shell script, por exemplo, em um script test.sh:

#!/bin/sh
mongo myDbName
db.mycollection.findOne()
show collections

Quando executo esse script via ./test.sh, a conexão com o MongoDB é estabelecida, mas os seguintes comandos não são executados.

Como executar outros comandos através do shell script test.sh?

StackOverFlow
fonte

Respostas:

452

Você também pode avaliar um comando usando o --evalsinalizador, se for apenas um único comando.

mongo --eval "printjson(db.serverStatus())"

Observe: se você estiver usando operadores Mongo, começando com um sinal $, deseje colocar o argumento eval entre aspas simples para impedir que o shell avalie o operador como uma variável de ambiente:

mongo --eval 'db.mycollection.update({"name":"foo"},{$set:{"this":"that"}});' myDbName

Caso contrário, você poderá ver algo assim:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :
theTuxRacer
fonte
35
Para .find()operações, você precisa chamar uma operação no objeto de resultado para imprimir os documentos, como toArray()ou shellPrint(). por exemplo,mongo userdb --eval "printjson(db.users.find().toArray())"
Gingi 19/06/2014
4
Eu tive que especificar a cadeia de conexão como mongo <ip>: <port> / db --eval "printjson (db.serverStatus ())" ou mongo <ip>: <port> / db <mongoCommands.js para impedir que sempre conectando ao "teste"
dev
9
Graças @Gingi - meu método preferido é mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()"... simples :)
Matt Fletcher
4
Eu gostaria de obter todos os resultados, em vez de vê-lo "digitar 'it' para mais"
Randy L
6
@ Amida, você pode fazer, mongo --eval "db.version()" --quietpor exemplo, para evitar imprimir todo o ruído que você diz #
Fermin Silva
327

Coloque seu script mongo em um .jsarquivo.

Então execute mongo < yourFile.js

Ex:

demo.js // arquivo possui seu script

use sample  //db name
show collections

mantenha esse arquivo em "c: \ db-scripts"

Em seguida, no prompt do cmd, vá para "c: \ db-scripts"

C:\db-scripts>mongo < demo.js

Isso executará o código no mongo e mostra a saída

C:\db-scripts>mongo < demo.js
Mongo shell version: 3.0.4
Connecting to: test
switched to db sample
users   //collection name
tasks   //collection name
bye
C:\db-scripts>
Matt
fonte
13
Muito literalmente ... você executa exatamente os mesmos comandos que introduziria no mongo shell, salva esses comandos em um .jsarquivo e os passa como parâmetro para o mongocomando.
Matt
7
Vale a pena notar que qualquer coisa que você definir em uma declaração --eval (se fornecida) para o intérprete mongo permanecerá no escopo quando seu script (se fornecido) for executado. Você pode usar isso para tornar seus scripts mais reutilizáveis, por exemplo. mongo --eval "somevar = 'someval';" db_name script_that_uses_somevar.js
Andrew J
9
@ Matt - Note que o não-JavaScript comandos que o shell fornece não estão disponíveis em um arquivo JavaScript executado, por isso use dbNamee show dbsvai trabalhar a partir do shell pronta interna, mas não de dentro de um .jsarquivo. Existem equivalentes JavaScript para os comandos não JavaScript, portanto, isso não é uma limitação, apenas algo que você precisa conhecer.
Tad Marshall
4
Se você precisa especificar um nome de um banco de dados, nome de usuário, senha, você pode fazermongo dbName -u userName -p "password with spaces" scriptToRun.js
KevinL
11
existe uma maneira de manter aberto o prompt do mongo? Também não quero que o mongo diga "tchau" para mim.
Alexander Mills
102

Isso funciona para mim no Linux:

mongo < script.js
Antonin Brettsnajdr
fonte
64

Coloque isso em um arquivo chamado test.js:

db.mycollection.findOne()
db.getCollectionNames().forEach(function(collection) {
  print(collection);
});

depois execute-o com mongo myDbName test.js.

Theo
fonte
2
Como passar valores para o script do bash? Eu quero inserir nome no db que está disponível em bash como variável e quero passá-lo para o script (JS)
Sasikanth
Esta é uma solução muito melhor. Quando canalizo um arquivo para o mongo, recebo erros de sintaxe js.
Storm Muller
41

Há uma página de documentação oficial sobre isso também.

Exemplos dessa página incluem:

mongo server:27017/dbname --quiet my_commands.js
mongo test --eval "printjson(db.getCollectionNames())"
thaddeusmt
fonte
32

O script de shell abaixo também funcionou bem para mim ... definitivamente tive que usar o redirecionamento que Antonin mencionou a princípio ... que me deu a ideia de testar o documento aqui.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}
David H. Young
fonte
13
Ótima resposta! Para vários comandos, isso também funciona:echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
Dennis Münkle 14/03
Definitivamente útil porque você não pode usar "use mydb" em um arquivo JS.
Buzypi
Obrigado por isso! Finalmente eu sou capaz de ligar use another_db. :-)
Ionică Bizău
11
Na verdade, você pode alternar DB partir de um script mongo:db = db.getSiblingDB('otherdb');
joeytwiddle
Apenas o que eu precisava. No entanto, se você precisar usar apenas um banco de dados, poderá passar o nome do banco de dados para o comando mongo, por exemplo, mongo mydb <<EOFetc.
spikyjt 25/02
22

Na minha configuração eu tenho que usar:

mongo --host="the.server.ip:port" databaseName theScript.js 
Ed Williams
fonte
20

Eu uso a sintaxe "heredoc", mencionada por David Young. Mas há um porém:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { $exists: true }
})
.forEach( printjson );
EOF

O exemplo acima NÃO funcionará, porque a frase "$ existe" será vista pelo shell e substituída pelo valor da variável de ambiente denominada "existe". Como, provavelmente, não existe, então após a expansão do shell, ele se torna:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { : true }
})
.forEach( printjson );
EOF

Para que ele passe, você tem duas opções. Um é feio, um é bastante agradável. Primeiro, o feio: escape dos sinais de $:

#!/usr/bin/sh

mongo <db> <<EOF
db.<collection>.find({
  fieldName: { \$exists: true }
})
.forEach( printjson );
EOF

Eu não recomendo isso, porque é fácil esquecer de escapar.

A outra opção é escapar do EOF, assim:

#!/usr/bin/sh

mongo <db> <<\EOF
db.<collection>.find({
  fieldName: { $exists: true }
})
.forEach( printjson );
EOF

Agora, você pode colocar todos os cifrões que deseja em seu heredoc, e os cifrões são ignorados. O lado negativo: Isso não funciona se você precisar colocar parâmetros / variáveis ​​do shell no seu script mongo.

Outra opção com a qual você pode brincar é mexer com seu shebang. Por exemplo,

#!/bin/env mongo
<some mongo stuff>

Existem vários problemas com esta solução:

  1. Só funciona se você estiver tentando tornar um script mongo executável a partir da linha de comando. Você não pode misturar comandos regulares do shell com comandos mongo shell. E tudo o que você economiza ao fazer isso é não precisar digitar "mongo" na linha de comando ... (razão suficiente, é claro)

  2. Funciona exatamente como "mongo <some-js-file>", o que significa que não permite que você use o comando "use <db>".

Tentei adicionar o nome do banco de dados ao shebang, o que você acha que funcionaria. Infelizmente, da maneira como o sistema processa a linha shebang, tudo após o primeiro espaço é passado como um único parâmetro (como se citado) para o comando env, e o env falha ao encontrá-lo e executá-lo.

Em vez disso, você deve incorporar a alteração do banco de dados no próprio script, da seguinte maneira:

#!/bin/env mongo
db = db.getSiblingDB('<db>');
<your script>

Como em qualquer coisa na vida, "há mais de uma maneira de fazer isso!"

John Arrowwood
fonte
18

Caso você tenha a autenticação ativada:

mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js
Moses Xu
fonte
16

Crie um arquivo de script; comandos de gravação:

#!/bin/sh
mongo < file.js

Na file.jsgravação sua consulta mongo:

db.collection.find({"myValue":null}).count();
GSK
fonte
13

Que tal agora:

echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
Mark Butler
fonte
11
Ou um pouco mais legível: echo "db.mycollection.findOne ()" | mongo myDbName --quiet | python -m json.tool
dirkaholic
Isso é útil para executar alguma coisa depois .mongorcfoi carregado ( docs.mongodb.org/manual/reference/program/mongo/... )
Gianfranco P.
12

Conforme sugerido por theTuxRacer, você pode usar o comando eval , para aqueles que o estão perdendo como eu, você também pode adicionar seu nome de banco de dados se não estiver tentando executar a operação no banco de dados padrão.

mongo <dbname> --eval "printjson(db.something.find())"
Matt Clark
fonte
7

Obrigado printf! Em um ambiente Linux, eis uma maneira melhor de ter apenas um arquivo executando o programa. Digamos que você tenha dois arquivos, mongoCmds.jscom vários comandos:

use someDb
db.someColl.find()

e então o arquivo do shell do driver, runMongoCmds.sh

mongo < mongoCmds.js

Em vez disso, tenha apenas um arquivo, runMongoCmds.sh contendo

printf "use someDb\ndb.someColl.find()" | mongo

O Bash's printfé muito mais robusto echoe permite que os \ncomandos entre eles os forcem em várias linhas.

tgoneil
fonte
7
mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF
Erdem ÖZDEMİR
fonte
6

No meu caso, eu posso usar convenientemente \ncomo separador para o próximo comando mongo que quero executar e canalizá-los paramongo

echo $'use your_db\ndb.yourCollection.find()' | mongo
Ardhi
fonte
4

O sinalizador --shell também pode ser usado para arquivos javascript

 mongo --shell /path/to/jsfile/test.js 
Jackson Harry
fonte
Eu acho que isso deixa o shell aberto depois que o js é executado? mongo /path/to/jsfile/test.jstambém executará o js.
UpTheCreek 18/01/19
4
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
Talespin_Kit
fonte
3

Migrado recentemente do mongodb para o Postgres. Foi assim que usei os scripts.

mongo < scripts.js > inserts.sql

Leia o scripts.jsredirecionamento e output para inserts.sql.

scripts.js se parece com isso

use myDb;
var string = "INSERT INTO table(a, b) VALUES";
db.getCollection('collectionName').find({}).forEach(function (object) {
    string += "('" + String(object.description) + "','" + object.name + "'),";
});
print(string.substring(0, string.length - 1), ";");

inserts.sql se parece com isso

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');
mythicalcoder
fonte
11
Muito interessante, mas fora de tópico em relação à pergunta original.
jlyonsmith
How to execute mongo commands through shell scripts?Isso não está fora do tópico. De fato, cheguei a essa pergunta devido ao título. Então, pessoas como eu se beneficiam lendo essa resposta. Além disso, estou fornecendo um método muito útil no exemplo, em vez de um exemplo de brinquedo.
Mythicalcoder
2

Se você quiser lidar com isso com uma linha, é uma maneira fácil.

file.sh --> db.EXPECTED_COLLECTION.remove("_id":1234)

cat file.sh | mongo <EXPECTED_COLLECTION>
Erçin Akçay
fonte
1

Eu escrevi as várias opções para executar um Shell Script Mongo de dentro de um script maior Bash

PKD
fonte
1

Solução de script de shell único com capacidade de passar argumentos mongo ( --quiet, dbname, etc):

#!/usr/bin/env -S mongo --quiet localhost:27017/test

cur = db.myCollection.find({});
while(cur.hasNext()) {
  printjson(cur.next());
}

O -Ssinalizador pode não funcionar em todas as plataformas.

yǝsʞǝla
fonte
0

Ao usar um replicaset, as gravações devem ser feitas no PRIMARY, portanto, geralmente uso uma sintaxe como essa, que evita ter que descobrir qual host é o mestre:

mongo -host myReplicaset/anyKnownReplica

Richard Salt
fonte