¿Cómo ejecutar comandos mongo a través de scripts de shell?

404

Quiero ejecutar mongocomandos en el script de shell, por ejemplo, en un script test.sh:

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

Cuando ejecuto este script vía ./test.sh, se establece la conexión con MongoDB, pero no se ejecutan los siguientes comandos.

¿Cómo ejecutar otros comandos a través del script de shell test.sh?

Desbordamiento de pila
fuente

Respuestas:

452

También puede evaluar un comando usando la --evalbandera, si es solo un comando.

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

Tenga en cuenta: si está utilizando operadores Mongo, comenzando con un signo $, querrá rodear el argumento eval entre comillas simples para evitar que el shell evalúe al operador como una variable de entorno:

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

De lo contrario, puede ver algo como esto:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :
theTuxRacer
fuente
35
Para las .find()operaciones, debe llamar a una operación en el objeto de resultado para imprimir los documentos, como toArray()o shellPrint(). por ejemplo,mongo userdb --eval "printjson(db.users.find().toArray())"
Gingi
44
Tuve que especificar la cadena de conexión como mongo <ip>: <port> / db --eval "printjson (db.serverStatus ())" o mongo <ip>: <port> / db <mongoCommands.js para evitar que siempre conectando a "prueba"
dev
99
Gracias @Gingi - mi método preferido es mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()"... simples :)
Matt Fletcher
44
desearía obtener TODOS los resultados, en lugar de verlo como "escriba 'it' para obtener más"
Randy L
66
@Amida que puedes hacer, mongo --eval "db.version()" --quietpor ejemplo, para evitar imprimir todo el ruido que dices
Fermín Silva
327

Pon tu script mongo en un .jsarchivo.

Luego ejecuta mongo < yourFile.js

Ex:

El archivo demo.js // tiene su script

use sample  //db name
show collections

mantenga este archivo en "c: \ db-scripts"

Luego, en cmd prompt, vaya a "c: \ db-scripts"

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

Esto ejecutará el código en mongo y muestra la salida

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>
Mate
fuente
13
Literalmente ... tomas exactamente los mismos comandos que ingresarías al shell mongo, guardas esos comandos en un .jsarchivo y los pasas como un parámetro al mongocomando.
Matt
77
Vale la pena señalar que todo lo que establezca en una declaración --eval (si se proporciona) al intérprete mongo permanecerá dentro del alcance cuando se ejecute su secuencia de comandos (si se proporciona). Puede usar esto para hacer que sus scripts sean más reutilizables, por ejemplo. mongo --eval "somevar = 'someval';" db_name script_that_uses_somevar.js
Andrew J
99
@ Matt - Tenga en cuenta que los comandos no JavaScript que proporciona la cáscara no están disponibles en un archivo JavaScript ejecutada, por lo que use dbName, y show dbstrabajará a partir de la cáscara pronta interna, pero no desde el interior de un .jsarchivo. Hay equivalentes de JavaScript para los comandos que no son de JavaScript, por lo que esto no es una limitación, solo algo que debe tener en cuenta.
Tad Marshall
44
Si necesita especificar el nombre de una base de datos, nombre de usuario, contraseña, puede hacerlomongo dbName -u userName -p "password with spaces" scriptToRun.js
KevinL
1
¿hay alguna manera de mantener abierto el indicador de mongo? AKA No quiero que Mongo me diga "adiós".
Alexander Mills
102

Esto funciona para mí en Linux:

mongo < script.js
Antonin Brettsnajdr
fuente
64

Pon esto en un archivo llamado test.js:

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

luego ejecútalo con mongo myDbName test.js.

Theo
fuente
2
¿Cómo pasar valores al script desde bash? Quiero insertar el nombre en db que está disponible en bash como variable y quiero pasarlo al script (js)
Sasikanth
Esta es una solución mucho mejor, cuando canalizo un archivo a mongo obtengo errores de sintaxis js.
Storm Muller
41

También hay una página de documentación oficial sobre esto.

Los ejemplos de esa página incluyen:

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

El siguiente script de shell también funcionó muy bien para mí ... definitivamente tuve que usar la redirección que Antonin mencionó al principio ... que me dio la idea de probar el documento aquí.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}
David H. Young
fuente
13
¡Gran respuesta! Para varios comandos, esto también funciona:echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
Dennis Münkle
Definitivamente útil porque no puede usar "use mydb" dentro de un archivo JS.
buzypi
¡Gracias por esto! Finalmente puedo llamar use another_db. :-)
Ionică Bizău
1
En realidad, puede cambiar DB desde un script mongo:db = db.getSiblingDB('otherdb');
joeytwiddle
Justo lo que necesitaba. Sin embargo, si solo necesita usar una base de datos, puede pasar el nombre de la base de datos al comando mongo, por ejemplo, mongo mydb <<EOFetc.
spikyjt
22

En mi configuración tengo que usar:

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

Uso la sintaxis "heredoc", que menciona David Young. Pero hay una trampa:

#!/usr/bin/sh

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

Lo anterior NO funcionará, porque la frase "$ existe" será vista por el shell y sustituida con el valor de la variable de entorno llamada "existe". Lo cual, probablemente, no existe, por lo que después de la expansión de shell, se convierte en:

#!/usr/bin/sh

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

Para que pase, tienes dos opciones. Uno es feo, uno es bastante agradable. Primero, el feo: escapar de los signos $:

#!/usr/bin/sh

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

NO recomiendo esto, porque es fácil olvidar escapar.

La otra opción es escapar del EOF, así:

#!/usr/bin/sh

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

Ahora, puede poner todos los signos de dólar que desee en su heredoc, y los signos de dólar se ignoran. El lado negativo: eso no funciona si necesita poner parámetros / variables de shell en su script mongo.

Otra opción con la que puedes jugar es meterse con tu shebang. Por ejemplo,

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

Hay varios problemas con esta solución:

  1. Solo funciona si intenta hacer que un script de shell mongo sea ejecutable desde la línea de comandos. No puede mezclar comandos de shell normales con comandos de shell mongo. Y todo lo que ahorra al hacerlo es no tener que escribir "mongo" en la línea de comando ... (razón suficiente, por supuesto)

  2. Funciona exactamente como "mongo <some-js-file>", lo que significa que no le permite usar el comando "use <db>".

Intenté agregar el nombre de la base de datos al shebang, que pensarías que funcionaría. Desafortunadamente, la forma en que el sistema procesa la línea shebang, todo después del primer espacio se pasa como un solo parámetro (como si fuera citado) al comando env, y env no puede encontrarlo ni ejecutarlo.

En cambio, debe incrustar el cambio de la base de datos dentro del script en sí, así:

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

Como con cualquier cosa en la vida, "¡hay más de una forma de hacerlo!"

John Arrowwood
fuente
18

En caso de que tenga habilitada la autenticación:

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

Crea un archivo de script; escribir comandos:

#!/bin/sh
mongo < file.js

En file.jsescriba su consulta mongo:

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

Qué tal esto:

echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
Mark Butler
fuente
1
O un poco más legible: echo "db.mycollection.findOne ()" | mongo myDbName --quiet | python -m json.tool
dirkaholic
Esto es útil para ejecutar algo después de que .mongorcse ha cargado ( docs.mongodb.org/manual/reference/program/mongo/… )
Gianfranco P.
12

Según lo sugerido theTuxRacer, puede usar el comando eval , para aquellos que lo faltan como yo, también puede agregar su nombre de base de datos si no está tratando de preformar la operación en la base de datos predeterminada.

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

Gracias printf! En un entorno Linux, aquí hay una mejor manera de hacer que solo un archivo ejecute el programa. Digamos que tiene dos archivos, mongoCmds.jscon múltiples comandos:

use someDb
db.someColl.find()

y luego el archivo shell del controlador, runMongoCmds.sh

mongo < mongoCmds.js

En su lugar, tenga solo un archivo, runMongoCmds.sh que contenga

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

Bash printfes mucho más robusto que echoy permite que los \ncomandos entre los fuercen en varias líneas.

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

En mi caso, puedo usar convenientemente \ncomo separador para el próximo comando mongo que quiero ejecutar y luego canalizarlos amongo

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

--la bandera también se puede usar para archivos javascript

 mongo --shell /path/to/jsfile/test.js 
Jackson Harry
fuente
Creo que esto deja el shell abierto después de que js sea ejecutado? mongo /path/to/jsfile/test.jsEjecutará el js también.
UpTheCreek
4
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
Talespin_Kit
fuente
3

Recientemente migró de mongodb a Postgres. Así es como usé los scripts.

mongo < scripts.js > inserts.sql

Lea la scripts.jsredirección de salida y hacia inserts.sql.

scripts.js Se ve como esto

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 ve como esto

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');
codificador mítico
fuente
1
Muy interesante, pero fuera de tema con respecto a la pregunta original.
jlyonsmith
How to execute mongo commands through shell scripts?Esto no está fuera de tema. De hecho, llegué a esta pregunta debido al título. Entonces, la gente como yo se beneficia al leer esa respuesta. Además, estoy dando un método muy útil en el ejemplo en lugar de un ejemplo de juguete.
mythicalcoder
2

Si desea manejarlo con una línea, es una manera fácil.

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

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

Yo escribí las diversas opciones para ejecutar una secuencia de comandos shell Mongo desde un script Bash más grande

PKD
fuente
1

Solución de script de shell único con capacidad para pasar argumentos mongo ( --quiet, dbname, etc.):

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

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

La -Sbandera podría no funcionar en todas las plataformas.

yǝsʞǝla
fuente
0

Cuando utilizo un conjunto de réplicas, las escrituras deben realizarse en PRIMARY, por lo que generalmente uso una sintaxis como esta que evita tener que averiguar qué host es el maestro:

mongo -host myReplicaset/anyKnownReplica

Richard Salt
fuente