Jak wykonywać polecenia mongo za pomocą skryptów powłoki?

403

Chcę wykonywać mongopolecenia w skrypcie powłoki, np. W skrypcie test.sh:

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

Kiedy wykonuję ten skrypt za pośrednictwem ./test.sh, połączenie z MongoDB jest ustanawiane, ale następujące polecenia nie są wykonywane.

Jak wykonać inne polecenia za pomocą skryptu powłoki test.sh?

Przepełnienie stosu
źródło

Odpowiedzi:

452

Możesz również ocenić polecenie za pomocą --evalflagi, jeśli jest to tylko jedno polecenie.

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

Uwaga: jeśli używasz operatorów Mongo, zaczynając od znaku $, powinieneś otoczyć argument eval pojedynczymi cudzysłowami, aby powstrzymać powłokę przed ocenianiem operatora jako zmiennej środowiskowej:

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

W przeciwnym razie możesz zobaczyć coś takiego:

mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY    SyntaxError: Unexpected token :
theTuxRacer
źródło
35
W przypadku .find()operacji należy wywołać operację na obiekcie wynikowym, aby wydrukować dokumenty, takie jak toArray()lub shellPrint(). np.mongo userdb --eval "printjson(db.users.find().toArray())"
Gingi
4
Musiałem określić parametry połączenia, takie jak mongo <ip>: <port> / db --eval "printjson (db.serverStatus ())" lub mongo <ip>: <port> / db <mongoCommands.js, aby zapobiec zawsze łączę się z „testem”
dev
9
Dzięki @Gingi - moją preferowaną metodą jest mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()"... simples :)
Matt Fletcher
4
chciałbym uzyskać WSZYSTKIE wyniki, zamiast widzieć, jak wypowiada „wpisz”, żeby uzyskać więcej ”
Randy L
6
@Amida możesz zrobić mongo --eval "db.version()" --quietna przykład, aby uniknąć drukowania całego hałasu, który mówisz
Fermin Silva,
327

Umieść skrypt mongo w .jspliku.

Następnie wykonaj mongo < yourFile.js

Dawny:

Plik demo.js // ma twój skrypt

use sample  //db name
show collections

przechowuj ten plik w „c: \ db-scripts”

Następnie w wierszu polecenia cmd przejdź do „c: \ db-scripts”

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

Spowoduje to wykonanie kodu w mongo i wyświetlenie wyniku

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
źródło
13
Całkiem dosłownie ... bierzesz dokładnie te same polecenia, które wprowadzasz do powłoki mongo, zapisujesz je w .jspliku i przekazujesz jako parametr do mongopolecenia.
Matt
7
Warto zauważyć, że wszystko, co ustawisz w instrukcji --eval (jeśli jest podana) interpretera mongo, pozostanie w zasięgu po wykonaniu skryptu (jeśli jest podany). Możesz użyć tego, aby skrypty były bardziej wielokrotnego użytku, np. mongo --eval "somevar = 'someval';" db_name script_that_uses_somevar.js
Andrew J
9
@Matt - Należy zauważyć, że zakaz JavaScript poleceń powłoki zapewnia, że nie są dostępne w zawartej pliku JavaScript, tak use dbNamei show dbsbędzie działać z nazwą powłoki wewnętrznej szybki, ale nie od wewnątrz .jspliku. Istnieją polecenia w języku JavaScript dla poleceń innych niż JavaScript, więc nie jest to ograniczenie, tylko coś, o czym musisz wiedzieć.
Tad Marshall
4
Jeśli musisz podać nazwę bazy danych, nazwę użytkownika, hasło, możesz to zrobićmongo dbName -u userName -p "password with spaces" scriptToRun.js
KevinL
1
Czy istnieje sposób, aby monit Mongo był otwarty? AKA Nie chcę, żeby Mongo powiedział mi „pa”.
Alexander Mills,
102

Działa to dla mnie pod Linuksem:

mongo < script.js
Antonin Brettsnajdr
źródło
64

Umieść to w pliku o nazwie test.js:

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

następnie uruchom go mongo myDbName test.js.

Theo
źródło
2
Jak przekazać wartości do skryptu z bash? Chcę wstawić nazwę do db, która jest dostępna w bash jako zmienna i chcę przekazać ją do skryptu (js)
Sasikanth
Jest to o wiele lepsze rozwiązanie, gdy przesyłam potok do pliku mongo, dostaję błędy składniowe js.
Storm Muller
41

Istnieje również oficjalna strona dokumentacji na ten temat.

Przykłady z tej strony to:

mongo server:27017/dbname --quiet my_commands.js
mongo test --eval "printjson(db.getCollectionNames())"
thaddeusmt
źródło
32

Poniższy skrypt powłoki również działał dobrze dla mnie ... zdecydowanie musiałem użyć przekierowania, o którym Antonin wspomniał na początku ... co dało mi pomysł na przetestowanie tego dokumentu.

function testMongoScript {
    mongo <<EOF
    use mydb
    db.leads.findOne()
    db.leads.find().count()
EOF
}
David H. Young
źródło
13
Świetna odpowiedź! Działa to również w przypadku wielu poleceń:echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
Dennis Münkle
Zdecydowanie przydatne, ponieważ nie można użyć „use mydb” w pliku JS.
buzypi
Dziękuję Ci za to! Wreszcie mogę zadzwonić use another_db. :-)
Ionică Bizău,
1
W rzeczywistości możesz przełączyć DB z poziomu skryptu mongo:db = db.getSiblingDB('otherdb');
joeytwiddle
Dokładnie to, czego potrzebowałem. Jednak jeśli potrzebujesz użyć tylko jednej bazy danych, możesz przekazać nazwę bazy danych do polecenia mongo, np. mongo mydb <<EOFItp.
spikyjt
22

W mojej konfiguracji muszę używać:

mongo --host="the.server.ip:port" databaseName theScript.js 
Ed Williams
źródło
19

Używam składni „heredoc”, o której wspomina David Young. Ale jest w tym haczyk:

#!/usr/bin/sh

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

Powyższe NIE zadziała, ponieważ wyrażenie „$ istnieje” będzie widziane przez powłokę i podstawione wartością zmiennej środowiskowej o nazwie „istnieje”. Co prawdopodobnie nie istnieje, więc po rozszerzeniu powłoki staje się:

#!/usr/bin/sh

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

Aby przejść, masz dwie opcje. Jeden jest brzydki, drugi jest całkiem fajny. Po pierwsze, brzydka: uciec od znaków $:

#!/usr/bin/sh

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

NIE polecam tego, ponieważ łatwo jest zapomnieć o ucieczce.

Inną opcją jest ucieczka przed EOF, tak jak to:

#!/usr/bin/sh

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

Teraz możesz umieścić wszystkie znaki dolara w swoim heredoc, a znaki dolara są ignorowane. Wada: To nie działa, jeśli musisz umieścić parametry / zmienne powłoki w skrypcie mongo.

Inną opcją, z którą możesz grać, jest bałagan z shebangiem. Na przykład,

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

Istnieje kilka problemów z tym rozwiązaniem:

  1. Działa to tylko wtedy, gdy próbujesz wykonać skrypt powłoki mongo jako wykonywalny z wiersza poleceń. Nie można łączyć zwykłych poleceń powłoki z poleceniami powłoki mongo. I jedyne, co oszczędzasz, robiąc to, nie musisz wpisywać „mongo” w wierszu poleceń ... (oczywiście wystarczający powód)

  2. Działa dokładnie jak „mongo <some-js-file>”, co oznacza, że ​​nie pozwala na użycie polecenia „use <db>”.

Próbowałem dodać nazwę bazy danych do shebang, co według ciebie byłoby skuteczne. Niestety, sposób, w jaki system przetwarza linię shebang, wszystko po pierwszym spacji jest przekazywane jako pojedynczy parametr (jak w cudzysłowie) do polecenia env, a env nie może go znaleźć i uruchomić.

Zamiast tego musisz osadzić zmianę bazy danych w samym skrypcie, tak:

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

Jak w przypadku wszystkiego w życiu, „istnieje więcej niż jeden sposób, aby to zrobić!”

John Arrowwood
źródło
18

Jeśli masz włączone uwierzytelnianie:

mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js
Mojżesz Xu
źródło
16

Utwórz plik skryptu; napisz polecenia:

#!/bin/sh
mongo < file.js

W file.jszapisie zapytanie Mongo:

db.collection.find({"myValue":null}).count();
GSK
źródło
13

Co powiesz na to:

echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
Mark Butler
źródło
1
Lub nieco bardziej czytelny: echo „db.mycollection.findOne ()” | mongo myDbName --quiet | python -m json.tool
dirkaholic
Jest to przydatne do wykonania czegoś po .mongorczaładowaniu ( docs.mongodb.org/manual/reference/program/mongo/… )
Gianfranco P.
12

Jak sugeruje theTuxRacer, możesz użyć polecenia eval , dla tych, którzy go brakuje, tak jak ja, możesz także dodać w nazwie db, jeśli nie próbujesz wykonać operacji na domyślnym db.

mongo <dbname> --eval "printjson(db.something.find())"
Matt Clark
źródło
7

Dziękuję printf! W środowisku Linux jest lepszy sposób na uruchomienie tylko jednego pliku. Załóżmy, że masz dwa pliki mongoCmds.jsz wieloma poleceniami:

use someDb
db.someColl.find()

a następnie plik powłoki sterownika, runMongoCmds.sh

mongo < mongoCmds.js

Zamiast tego, masz tylko jeden plik, zawierający runMongoCmds.sh

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

Bash printfjest znacznie bardziej niezawodny echoi pozwala na \nwymuszanie poleceń między wieloma liniami.

tgoneil
źródło
7
mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF
Erdem ÖZDEMİR
źródło
6

W moim przypadku mogę wygodnie użyć \njako separatora dla następnego polecenia mongo, które chcę wykonać, a następnie potokować jemongo

echo $'use your_db\ndb.yourCollection.find()' | mongo
Ardhi
źródło
4

Flaga --shell może być również używana do plików javascript

 mongo --shell /path/to/jsfile/test.js 
Jackson Harry
źródło
Myślę, że to pozostawia otwartą powłokę po wykonaniu js? mongo /path/to/jsfile/test.jsbędzie również egzekwować js.
UpTheCreek
4
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
Talespin_Kit
źródło
3

Ostatnio migrowałem z mongodb do Postgres. Tak korzystałem ze skryptów.

mongo < scripts.js > inserts.sql

Przeczytaj scripts.jsi przekieruj wyjście na inserts.sql.

scripts.js wygląda tak

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 wygląda tak

INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');
mityczny koder
źródło
1
Bardzo interesujące, ale nie na temat oryginalnego pytania.
jlyonsmith
How to execute mongo commands through shell scripts?To nie jest nie na temat. W rzeczywistości dotarłem do tego pytania z powodu tytułu. Więc ludzie tacy jak ja korzystają z czytania takiej odpowiedzi. Daję też bardzo przydatną metodę w tym przykładzie, a nie zabawkę.
mityczny
2

Jeśli chcesz poradzić sobie z jedną linią, jest to łatwy sposób.

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

cat file.sh | mongo <EXPECTED_COLLECTION>
Erçin Akçay
źródło
1

I pisał się różne opcje Uruchamianie Mongo Shell Script od wewnątrz większego skryptu bash

PKD
źródło
1

Skrypt jednopowłokowy z możliwością przekazywania argumentów mongo ( --quiet, dbname itp.):

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

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

-SFlaga może nie działać na wszystkich platformach.

yǝsʞǝla
źródło
0

Podczas korzystania z replikaseta zapisy muszą być wykonywane na PODSTAWOWEJ, więc zwykle używam takiej składni, co pozwala uniknąć konieczności ustalania, który host jest nadrzędny:

mongo -host myReplicaset/anyKnownReplica

Richard Salt
źródło