Wie führe ich Mongo-Befehle über Shell-Skripte aus?


403

Ich möchte mongoBefehle in einem Shell-Skript ausführen , z. B. in einem Skript test.sh:

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

Wenn ich dieses Skript über ausführe ./test.sh, wird die Verbindung zu MongoDB hergestellt, aber die folgenden Befehle werden nicht ausgeführt.

Wie führe ich andere Befehle über ein Shell-Skript aus test.sh?

Antworten:


452

Sie können einen Befehl auch mit dem --evalFlag auswerten , wenn es sich nur um einen einzelnen Befehl handelt.

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

Bitte beachten Sie: Wenn Sie Mongo-Operatoren verwenden, beginnend mit einem $ -Zeichen, sollten Sie das eval-Argument in einfache Anführungszeichen setzen, damit die Shell den Operator nicht als Umgebungsvariable auswertet:

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

Andernfalls sehen Sie möglicherweise Folgendes:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :

35
Für .find()Vorgänge müssen Sie einen Vorgang für das Ergebnisobjekt aufrufen, um die Dokumente wie toArray()oder zu drucken shellPrint(). zBmongo userdb --eval "printjson(db.users.find().toArray())"
Gingi

4
Ich musste die Verbindungszeichenfolge wie mongo <ip>: <port> / db --eval "printjson (db.serverStatus ())" oder mongo <ip>: <port> / db <mongoCommands.js angeben, um dies zu verhindern Immer eine Verbindung zu "test"
dev

9
Danke @Gingi - meine bevorzugte Methode ist mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()"... simples :)
Matt Fletcher

4
Ich wünschte, ich würde ALLE Ergebnisse erhalten, anstatt zu sehen, wie es "Tippe es für mehr"
Randy L

6
@ Amida können Sie mongo --eval "db.version()" --quietzum Beispiel tun, um zu vermeiden, alle Geräusche zu drucken, die Sie sagen
Fermin Silva

327

Fügen Sie Ihr Mongo-Skript in eine .jsDatei ein.

Dann ausführen mongo < yourFile.js

Ex:

Die Datei demo.js // enthält Ihr Skript

use sample  //db name
show collections

Bewahren Sie diese Datei in "c: \ db-scripts" auf.

Gehen Sie dann in der cmd-Eingabeaufforderung zu "c: \ db-scripts".

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

Dadurch wird der Code in Mongo ausgeführt und die Ausgabe angezeigt

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>

13
Im wahrsten Sinne des Wortes ... Sie nehmen genau die gleichen Befehle, die Sie in die Mongo-Shell eingeben würden, speichern diese Befehle in einer .jsDatei und übergeben sie als Parameter an den mongoBefehl.
Matt

7
Es ist erwähnenswert, dass alles, was Sie in einer --eval-Anweisung (falls angegeben) für den Mongo-Interpreter festgelegt haben, bei der Ausführung Ihres Skripts (falls angegeben) im Gültigkeitsbereich bleibt. Sie können dies verwenden, um Ihre Skripte wiederverwendbarer zu machen, z. mongo --eval "somevar = 'someval';" db_name script_that_uses_somevar.js
Andrew J

9
@ Matt - Beachten Sie, dass die Nicht-JavaScript - Befehle , die die Shell bietet sind nicht in einer ausgeführten JavaScript - Datei, so use dbNameund show dbswird von der Shell internen Prompt arbeiten , aber nicht aus dem Innern einer .jsDatei. Es gibt JavaScript-Entsprechungen für Nicht-JavaScript-Befehle. Dies ist also keine Einschränkung, sondern nur etwas, das Sie beachten müssen.
Tad Marshall

4
Wenn Sie einen Namen einer Datenbank, einen Benutzernamen und ein Passwort angeben müssen, können Sie dies tunmongo dbName -u userName -p "password with spaces" scriptToRun.js
KevinL

1
Gibt es eine Möglichkeit, die Mongo-Eingabeaufforderung offen zu halten? AKA Ich möchte nicht, dass Mongo sich von mir verabschiedet.
Alexander Mills


64

Fügen Sie dies in eine Datei mit dem Namen ein test.js:

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

dann starte es mit mongo myDbName test.js.


2
Wie übergebe ich Werte von bash an das Skript? Ich möchte einen Namen in db einfügen, der in bash als Variable verfügbar ist, und ich möchte ihn an script (js) übergeben
Sasikanth

Dies ist eine viel bessere Lösung. Wenn ich eine Datei an mongo weitergebe, werden JS-Syntaxfehler angezeigt.
Storm Muller


32

Das Shell-Skript unten funktionierte auch gut für mich ... definitiv musste ich die Umleitung verwenden, die Antonin zuerst erwähnte ... das brachte mich auf die Idee, das hier gezeigte Dokument zu testen.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}

13
Gute Antwort! Für mehrere Befehle funktioniert dies auch:echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
Dennis Münkle

Auf jeden Fall nützlich, da Sie "use mydb" nicht in einer JS-Datei verwenden können.
Buzypi

Danke dafür! Endlich kann ich anrufen use another_db. :-)
Ionică Bizău

1
Tatsächlich können Sie die db = db.getSiblingDB('otherdb');
Datenbank

Genau das, was ich brauchte. Wenn Sie jedoch nur eine Datenbank verwenden müssen, können Sie den Datenbanknamen an den Befehl mongo mydb <<EOF
mongo übergeben

22

In meinem Setup muss ich verwenden:

mongo --host="the.server.ip:port" databaseName theScript.js 

20

Ich verwende die "Heredoc" -Syntax, die David Young erwähnt. Aber es gibt einen Haken:

#!/usr/bin/sh

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

Das Obige funktioniert NICHT, da der Ausdruck "$ existiert" von der Shell gesehen und durch den Wert der Umgebungsvariablen mit dem Namen "existiert" ersetzt wird. Was wahrscheinlich nicht existiert, also wird es nach der Shell-Erweiterung:

#!/usr/bin/sh

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

Um es passieren zu lassen, haben Sie zwei Möglichkeiten. Einer ist hässlich, einer ist ganz nett. Erstens die hässliche: Entkomme den $ -Zeichen:

#!/usr/bin/sh

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

Ich empfehle dies NICHT, da es leicht ist, die Flucht zu vergessen.

Die andere Möglichkeit besteht darin, dem EOF wie folgt zu entkommen:

#!/usr/bin/sh

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

Jetzt können Sie alle gewünschten Dollarzeichen in Ihren Heredoc einfügen, und die Dollarzeichen werden ignoriert. Die Kehrseite: Das funktioniert nicht, wenn Sie Shell-Parameter / -Variablen in Ihr Mongo-Skript einfügen müssen.

Eine andere Möglichkeit, mit der Sie spielen können, besteht darin, sich mit Ihrem Schebang anzulegen. Zum Beispiel,

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

Bei dieser Lösung gibt es mehrere Probleme:

  1. Es funktioniert nur, wenn Sie versuchen, ein Mongo-Shell-Skript über die Befehlszeile ausführbar zu machen. Sie können keine regulären Shell-Befehle mit Mongo-Shell-Befehlen mischen. Und alles, was Sie dadurch sparen, ist, dass Sie nicht "mongo" in die Befehlszeile eingeben müssen ... (Grund genug natürlich)

  2. Es funktioniert genau wie "mongo <some-js-file>", was bedeutet, dass Sie den Befehl "use <db>" nicht verwenden können.

Ich habe versucht, den Datenbanknamen zum Shebang hinzuzufügen, was Ihrer Meinung nach funktionieren würde. Leider wird bei der Art und Weise, wie das System die Shebang-Zeile verarbeitet, alles nach dem ersten Leerzeichen als einzelner Parameter (wie angegeben) an den Befehl env übergeben, und env kann ihn nicht finden und ausführen.

Stattdessen müssen Sie die Datenbankänderung wie folgt in das Skript selbst einbetten:

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

Wie bei allem im Leben gibt es "mehr als einen Weg, dies zu tun!"


18

Falls Sie die Authentifizierung aktiviert haben:

mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js

16

Erstellen Sie eine Skriptdatei. Schreibbefehle:

#!/bin/sh
mongo < file.js

In file.jsSchreiben Sie Ihre Mongo Abfrage:

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


12

Wie von vorgeschlagen theTuxRacer, können Sie den Befehl eval verwenden . Für diejenigen, denen er wie ich fehlt, können Sie auch Ihren Datenbanknamen hinzufügen, wenn Sie nicht versuchen, eine Operation für die Standarddatenbank durchzuführen.

mongo <dbname> --eval "printjson(db.something.find())"

7

Danke printf! In einer Linux-Umgebung ist es besser, wenn nur eine Datei die Show ausführt. Angenommen, Sie haben zwei Dateien mongoCmds.jsmit mehreren Befehlen:

use someDb
db.someColl.find()

und dann die Treiber-Shell-Datei, runMongoCmds.sh

mongo < mongoCmds.js

Verwenden Sie stattdessen nur eine Datei, die runMongoCmds.sh enthält

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

Bash's printfist viel robuster als echound ermöglicht es den \nZwischenbefehlen, sie in mehreren Zeilen zu erzwingen.



6

In meinem Fall kann ich bequem \nals Trennzeichen für den nächsten Mongo-Befehl verwenden, den ich ausführen möchte, und ihn dann weiterleitenmongo

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

4

Das Flag --shell kann auch für Javascript-Dateien verwendet werden

 mongo --shell /path/to/jsfile/test.js 

Ich denke, dies lässt die Shell nur offen, nachdem js ausgeführt wurde? mongo /path/to/jsfile/test.jswird auch die js ausführen.
UpTheCreek

4
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"

3

Kürzlich von Mongodb nach Postgres migriert. So habe ich die Skripte verwendet.

mongo < scripts.js > inserts.sql

Lesen Sie die scripts.jsund geben Sie die Umleitung an aus inserts.sql.

scripts.js sieht aus wie das

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 sieht aus wie das

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');

1
Sehr interessant, aber in Bezug auf die ursprüngliche Frage nicht zum Thema.
Jlyonsmith

How to execute mongo commands through shell scripts?Dies ist kein Off-Topic. Tatsächlich habe ich diese Frage aufgrund des Titels erreicht. Leute wie ich profitieren davon, eine solche Antwort zu lesen. Außerdem gebe ich im Beispiel eher eine sehr nützliche Methode als ein Spielzeugbeispiel.
mythicalcoder

2

Wenn Sie es mit einer Zeile behandeln möchten, ist dies ein einfacher Weg.

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

cat file.sh | mongo <EXPECTED_COLLECTION>

1

Ich schrieb auf die verschiedenen Optionen für das Ausführen eines Mongo Shell - Skript aus innerhalb eines größeren Bash - Skript


1

Single-Shell- --quietSkriptlösung mit der Fähigkeit, Mongo-Argumente ( , Datenbankname usw.) zu übergeben:

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

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

Das -SFlag funktioniert möglicherweise nicht auf allen Plattformen.


0

Wenn Sie ein Replikat verwenden, müssen Schreibvorgänge auf dem PRIMARY ausgeführt werden. Daher verwende ich normalerweise eine solche Syntax, um nicht herausfinden zu müssen, welcher Host der Master ist:

mongo -host myReplicaset/anyKnownReplica

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.