Comment exécuter des commandes mongo via des scripts shell?

404

Je veux exécuter des mongocommandes dans un script shell, par exemple dans un script test.sh:

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

Lorsque j'exécute ce script via ./test.sh, la connexion à MongoDB est établie, mais les commandes suivantes ne sont pas exécutées.

Comment exécuter d'autres commandes via un script shell test.sh?

StackOverFlow
la source

Réponses:

452

Vous pouvez également évaluer une commande à l'aide de l' --evalindicateur, s'il ne s'agit que d'une seule commande.

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

Remarque: si vous utilisez des opérateurs Mongo, en commençant par un signe $, vous souhaiterez entourer l'argument eval entre guillemets simples pour empêcher le shell d'évaluer l'opérateur en tant que variable d'environnement:

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

Sinon, vous pouvez voir quelque chose comme ceci:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :
theTuxRacer
la source
35
Pour les .find()opérations, vous devez appeler une opération sur l'objet résultat pour imprimer les documents, tels que toArray()ou shellPrint(). par exemple,mongo userdb --eval "printjson(db.users.find().toArray())"
Gingi
4
J'ai dû spécifier la chaîne de connexion comme mongo <ip>: <port> / db --eval "printjson (db.serverStatus ())" ou mongo <ip>: <port> / db <mongoCommands.js pour l'empêcher de toujours connecté à "test"
dev
9
Merci @Gingi - ma méthode préférée est mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()"... simples :)
Matt Fletcher
4
j'aurais aimé obtenir TOUS les résultats, au lieu de le voir "taper 'it' pour plus"
Randy L
6
@Amida, vous pouvez faire mongo --eval "db.version()" --quietpar exemple pour éviter d'imprimer tout le bruit que vous dites
Fermin Silva
327

Mettez votre script mongo dans un .jsfichier.

Ensuite, exécutez mongo < yourFile.js

Ex:

demo.js // le fichier a votre script

use sample  //db name
show collections

conservez ce fichier dans "c: \ db-scripts"

Ensuite, dans l'invite cmd, accédez à "c: \ db-scripts"

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

Cela exécutera le code en mongo et affichera la sortie

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>
Mat
la source
13
Littéralement .. vous prenez exactement les mêmes commandes que vous entreriez dans le shell mongo, enregistrez ces commandes dans un .jsfichier et passez-les en paramètre à la mongocommande.
Matt
7
Il convient de noter que tout ce que vous définissez dans une instruction --eval (si fournie) pour l'interpréteur mongo restera dans la portée lorsque votre script (si fourni) est exécuté. Vous pouvez l'utiliser pour rendre vos scripts plus réutilisables, par exemple. mongo --eval "somevar = 'someval';" db_name script_that_uses_somevar.js
Andrew J
9
@Matt - Notez que les commandes non JavaScript fournies par le shell ne sont pas disponibles dans un fichier JavaScript exécuté, use dbNameet show dbsfonctionneront donc à partir de l'invite interne du shell mais pas à l'intérieur d'un .jsfichier. Il existe des équivalents JavaScript pour les commandes non JavaScript, il ne s'agit donc pas d'une limitation, mais d'une chose dont vous devez être conscient.
Tad Marshall
4
Si vous devez spécifier le nom d'une base de données, le nom d'utilisateur, le mot de passe, vous pouvez le faire mongo dbName -u userName -p "password with spaces" scriptToRun.js
KevinL
1
existe-t-il un moyen de garder l'invite mongo ouverte? AKA Je ne veux pas que mongo me dise "au revoir".
Alexander Mills
102

Cela fonctionne pour moi sous Linux:

mongo < script.js
Antonin Brettsnajdr
la source
64

Mettez ceci dans un fichier appelé test.js:

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

puis lancez-le avec mongo myDbName test.js.

Théo
la source
2
Comment passer des valeurs au script depuis bash? Je veux insérer un nom dans db qui est disponible dans bash en tant que variable et je veux le passer au script (js)
Sasikanth
C'est une bien meilleure solution. Lorsque je redirige un fichier vers mongo, j'obtiens des erreurs de syntaxe js.
Storm Muller
41

Il existe une documentation officielle page de officielle à ce sujet.

Voici des exemples de cette page:

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

Le script shell ci-dessous a également bien fonctionné pour moi ... il fallait certainement utiliser la redirection qu'Antonin a mentionnée au début ... qui m'a donné l'idée de tester le document ici.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}
David H. Young
la source
13
Très bonne réponse! Pour plusieurs commandes, cela fonctionne également:echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
Dennis Münkle
Certainement utile car vous ne pouvez pas utiliser "use mydb" dans un fichier JS.
buzypi
Merci pour ça! Enfin je peux appeler use another_db. :-)
Ionică Bizău
1
En fait, vous pouvez changer de base de données à partir d'un script mongo:db = db.getSiblingDB('otherdb');
joeytwiddle
Juste ce dont j'avais besoin. Cependant, si vous n'avez besoin que d'une seule base de données, vous pouvez transmettre le nom de la base de données à la commande mongo, par exemple, mongo mydb <<EOFetc.
spikyjt
22

Dans ma configuration, je dois utiliser:

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

J'utilise la syntaxe "heredoc", que David Young mentionne. Mais il ya un hic:

#!/usr/bin/sh

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

Ce qui précède ne fonctionnera PAS, car l'expression «$ existe» sera vue par le shell et remplacée par la valeur de la variable d'environnement nommée «existe». Ce qui, probablement, n'existe pas, donc après l'expansion du shell, cela devient:

#!/usr/bin/sh

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

Pour le faire passer, vous avez deux options. On est moche, on est plutôt sympa. Tout d'abord, le laid: échapper aux signes $:

#!/usr/bin/sh

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

Je ne le recommande PAS, car il est facile d'oublier de s'échapper.

L'autre option est d'échapper à l'EOF, comme ceci:

#!/usr/bin/sh

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

Maintenant, vous pouvez mettre tous les signes dollar que vous souhaitez dans votre hérédoc, et les signes dollar sont ignorés. L'inconvénient: cela ne fonctionne pas si vous devez mettre des paramètres / variables shell dans votre script mongo.

Une autre option avec laquelle vous pouvez jouer est de jouer avec votre shebang. Par exemple,

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

Il y a plusieurs problèmes avec cette solution:

  1. Cela ne fonctionne que si vous essayez de rendre un script shell mongo exécutable à partir de la ligne de commande. Vous ne pouvez pas mélanger des commandes shell standard avec des commandes shell mongo. Et tout ce que vous économisez en le faisant, c'est de ne pas avoir à taper "mongo" sur la ligne de commande ... (raison suffisante, bien sûr)

  2. Il fonctionne exactement comme "mongo <some-js-file>" ce qui signifie qu'il ne vous permet pas d'utiliser la commande "use <db>".

J'ai essayé d'ajouter le nom de la base de données au shebang, ce qui pourrait fonctionner. Malheureusement, la façon dont le système traite la ligne shebang, tout ce qui se trouve après le premier espace est passé en tant que paramètre unique (comme s'il était cité) à la commande env, et env ne parvient pas à le trouver et à l'exécuter.

Au lieu de cela, vous devez intégrer la modification de la base de données dans le script lui-même, comme ceci:

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

Comme pour tout dans la vie, "il y a plus d'une façon de le faire!"

John Arrowwood
la source
18

Si l'authentification est activée:

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

Créez un fichier de script; écrire des commandes:

#!/bin/sh
mongo < file.js

En file.jsécrivant votre requête mongo:

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

Que dis-tu de ça:

echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
Mark Butler
la source
1
Ou un peu plus lisible: echo "db.mycollection.findOne ()" | mongo myDbName --quiet | python -m json.tool
dirkaholic
Ceci est utile pour exécuter quelque chose après .mongorcavoir été chargé ( docs.mongodb.org/manual/reference/program/mongo/… )
Gianfranco P.
12

Comme suggéré par theTuxRacer, vous pouvez utiliser la commande eval , pour ceux qui la manquent comme moi, vous pouvez également ajouter votre nom de base de données si vous n'essayez pas d'effectuer une opération sur la base de données par défaut.

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

Je vous remercie printf! Dans un environnement Linux, voici une meilleure façon d'avoir un seul fichier pour exécuter le show. Supposons que vous ayez deux fichiers, mongoCmds.jsavec plusieurs commandes:

use someDb
db.someColl.find()

puis le fichier shell du pilote, runMongoCmds.sh

mongo < mongoCmds.js

Au lieu de cela, ayez un seul fichier, runMongoCmds.sh contenant

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

Bash printfest beaucoup plus robuste echoet permet aux \ncommandes entre de les forcer sur plusieurs lignes.

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

Dans mon cas, je peux facilement utiliser \ncomme séparateur pour la prochaine commande mongo que je veux exécuter, puis les diriger versmongo

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

Le drapeau --shell peut également être utilisé pour les fichiers javascript

 mongo --shell /path/to/jsfile/test.js 
Jackson Harry
la source
Je pense que cela laisse simplement le shell ouvert après l'exécution de js? mongo /path/to/jsfile/test.jsexécutera le js aussi.
UpTheCreek
4
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
Talespin_Kit
la source
3

A récemment migré de mongodb vers Postgres. C'est ainsi que j'ai utilisé les scripts.

mongo < scripts.js > inserts.sql

Lisez la scripts.jsredirection et la sortie vers inserts.sql.

scripts.js ressemble à ça

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 ressemble à ça

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');
mythicalcoder
la source
1
Très intéressant, mais hors sujet par rapport à la question d'origine.
jlyonsmith
How to execute mongo commands through shell scripts?Ce n'est pas hors sujet. En fait, j'ai atteint cette question en raison du titre. Les gens comme moi ont donc intérêt à lire une telle réponse. En outre, je donne une méthode très utile dans l'exemple plutôt qu'un exemple de jouet.
mythicalcoder
2

Si vous voulez le gérer avec une seule ligne, c'est un moyen simple.

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

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

J'ai écrit les différentes options pour exécuter un script Shell Mongo à partir d'un script Bash plus grand

PKD
la source
1

Solution de script shell unique avec possibilité de passer des arguments mongo ( --quiet, dbname, etc.):

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

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

Le -Sdrapeau peut ne pas fonctionner sur toutes les plateformes.

yǝsʞǝla
la source
0

Lorsque vous utilisez un jeu de réplicas, les écritures doivent être effectuées sur le PRIMARY, donc j'utilise généralement une syntaxe comme celle-ci qui évite d'avoir à déterminer quel hôte est le maître:

mongo -host myReplicaset/anyKnownReplica

Richard Salt
la source