back to top

Mongosh: la nuova shell di MongoDB

mongosh è la nuova shell di MongoDB che sostituisce mongo. Al contrario di quest’ultima, non viene distribuita insieme a mongod, ma deve essere installata separatamente. Nelle precedenti lezioni, abbiamo già visto che su Windows basta eseguire il download e l’installazione del corrispondente pacchetto .msi, mentre su macOS viene automaticamente installata se si usa Homebrew.

mongosh è un ambiente di programmazione interattivo in cui possiamo non solo interrogare il database, ma anche eseguire qualsiasi comando Javascript.

Per cui, una volta avviata mongosh, possiamo eseguire del codice Javascript come mostrato nell’esempio sottostante.

myDb> function foo() { console.log('foo')}
[Function: foo]
myDb> foo()
foo

Abbiamo accesso completo a tutti gli oggetti, metodi e strutture di controllo del linguaggio. Per esempio, nel frammento di codice sottostante creiamo un array di 3 elementi il cui valore corrisponde al loro indice. Attraverso la funzione Array.prototype.map() moltiplichiamo ciascun elemento dell’array per 2. Infine otteniamo la somma degli elementi con Array.prototype.reduce().

myDb> Array.from(
  {length: 3}, 
  (_, index) => index
).map(e => e * 2).reduce((prev, current) => prev + current)
6

Comandi utili della shell

Dopo aver effettuato l’installazione ed essersi assicurati di aver configurato correttamente la variabile di ambiente PATH, possiamo aprire il terminale ed eseguire il comando mongosh --version per verificare qual è la versione corrente installata. Per un elenco dettagliato di tutte le opzioni disponibili basterà invece eseguire mongosh --help.

Se abbiamo installato MongoDB sul nostro computer (nella seconda lezione abbiamo spiegato come fare e come lanciare un’istanza di mongod), possiamo collegarci al server locale eseguendo mongosh nel terminale senza nessuna opzione. Questo comando è equivalente a mongosh --host 127.0.0.1 --port 27017 in cui 127.0.0.1 è l’indirizzo IPv4 di localhost e 27017 è la porta predefinita usata da MongoDB. Se vogliamo selezionare un determinato database, possiamo indicarlo come primo argomento di mongosh <nome-database>. Per esempio, se lanciamo il comando mongosh ristoranti --port 27017, ci colleghiamo al server locale e selezioniamo come database ‘ristoranti’.

Una volta eseguito l’accesso, visualizzeremo delle informazioni in merito alla connessione. Al primo accesso potrebbe esser mostrato un avviso in cui si segnala che verranno raccolti dei dati di diagnostica in forma anonima. Possiamo disabilitare questa funzione eseguendo disableTelemetry().

Il prompt della shell di MongoDB mostra delle informazioni utili. Se abbiamo effettuato il collegamento al server locale, sarà mostrato il nome del database corrente seguito dal carattere ‘>’. Per esempio, se ci appare il prompt ristoranti>, vuol dire che il database corrente selezionato è ristoranti.

Possiamo avere conferma di qual è il database corrente con il comando:

ristoranti> db
ristoranti

Se vogliamo invece visualizzare l’elenco in ordine alfabetico di tutti i database presenti, eseguiremo show dbs.

ristoranti> show dbs
admin                 41 kB
blog                57.3 kB
cars                1.95 MB
config               111 kB
local                115 kB
movies              73.7 kB
music               65.2 MB
ristoranti          6.24 MB

Alcuni database come admin, local, config sono creati automaticamente da MongoDB e contengono delle informazioni necessarie al corretto funzionamento del server.

Per selezionare un altro database, occorre invece lanciare il comando use <nome_del_database_senza_parentesi_angolari>. Per esempio:

ristoranti> use cars
switched to db cars

Da questo momento, i comandi che eseguiamo per leggere o scrivere dei dati nelle collezioni, non si riferiranno più al database ristoranti, ma verranno indirizzati al database cars.

Per creare un nuovo database, useremo sempre il comando use seguito dal nome del nuovo database.

ristoranti> use hotel
switched to db hotel

Con l’ultimo comando abbiamo attivato un nuovo database ‘hotel’ che però non contiene alcuna collezione e per questo motivo non verrà nemmeno mostrato nell’elenco del comando show dbs. Inoltre se usciamo da mongosh col comando exit ed effettuiamo nuovamente l’accesso non ci sarà traccia del database ‘hotel’.

Per creare effettivamente il database dovremo aggiungere delle collezioni. Un primo modo per farlo è attraverso il comando db.createCollection("nome-db"[, oggetto_di_opzioni_facoltativo]).

Trascuriamo le opzioni facoltative e creiamo invece una semplice collezione vuota che chiamiamo ‘rooms’ all’interno del database ‘hotel’.

In base a quanto abbiamo detto prima, dovremo prima di tutto assicurarci che il database corrente sia quello corretto (possiamo vederlo dal prompt oppure eseguendo il comando db o possiamo banalmente eseguire use hotel) e creiamo poi al suo interno la nuova collezione.

hotel> use hotel
already on db hotel
hotel> db.createCollection('rooms')
{ ok: 1 }

A questo punto show dbs mostrerà anche il nome del database hotel.

Per visualizzare invece le collezioni presenti nel database corrente, useremo il comando show collections.

hotel> show collections
rooms

Se vogliamo eliminare una collezione, dovremo eseguire il comando db.collection.drop(). Per esempio, supponiamo di avere aggiunto un’altra collezione ‘room’.

hotel> show collections
rooms
room

Se volessimo eliminare ‘room’, dovremmo eseguire db.room.drop() che elimina la collezione ed eventuali indici associati.

hotel> db.room.drop()
true

Per rinominare invece la collezione ‘rooms’, usiamo il comando db.collection.renameCollection("nuovo-nome-collezione", dropCollectionFlag). Il secondo argomento è di tipo booleano. Il valore predefinito è false. Se pari a true, la collezione viene prima rimossa e poi viene creata una nuova collezione col nuovo nome.

Per provare la funzione di auto completamento, possiamo iniziare a digitare db.rooms.r e premiamo il tasto TAB.

hotel> db.room.r #premiamo il tasto TAB
db.rooms.renameCollection
db.rooms.replaceOne
db.rooms.reIndex
db.rooms.runCommand

Verrà mostrato un elenco dei metodi disponibili per la collezione. Usiamo quindi renameCollection() per cambiare il nome della collezione da ‘rooms’ a ‘room’.

hotel> db.rooms.renameCollection('room')
{ ok: 1 }

Se proviamo ad inserire uno o più documenti in una collezione non esistente con db.collection.insertOne() o db.collection.insertMany(), verrà automaticamente creata la collezione e popolata con i nuovi documenti.

hotel> show collections
rooms

Nel frammento di codice sottostante creiamo una nuova collezione aggiungendo il primo documento. Notiamo alcuni particolari interessanti. Dopo aver digitato db.guests.insertOne( premiamo il tasto INVIO per andare a capo. Mongosh capisce che non abbiamo finito di digitare l’intera istruzione e ci permette di continuare sulla riga successiva. I puntini all’inizio della riga indicano il livello di indentazione. Ogni volta che premiamo INVIO, Mongosh inizierà una nuova riga. Al termine dell’intero comando, verrà inserito un nuovo documento all’interno della collezione guests. È bene evidenziare che possiamo anche digitare campi e valori del nuovo documento senza attenerci strettamente alla sintassi JSON. Quello inserito non rappresenta un documento JSON valido. Ciò nonostante, Mongosh non impone regole restrittive e consente comunque di inserire il documento nella collezione guests. MongoDB conferma se il documento è stato inserito nella collezione ed indica anche il valore del campo _id del nuovo documento.

hotel> db.guests.insertOne(
... {
..... guest_id: 1,
..... booking_id: 1,
..... first_name: 'John',
..... last_name: 'Doe'
..... }
... )
{
  acknowledged: true,
  insertedId: ObjectId("621fc7b9d1e7cc6351038a29")
}

Possiamo assicurarci che la nuova collezione sia stata correttamente creata con show collections.

Visualizziamo invece un documento della collezione grazie a db.guests.findOne().

hotel> db.guests.findOne()
{
  _id: ObjectId("621fc7b9d1e7cc6351038a29"),
  guest_id: 1,
  booking_id: 1,
  first_name: 'John',
  last_name: 'Doe'
}

Se non passiamo alcun argomento, db.collection.findOne() restituisce un solo documento della collezione con tutti i suoi campi. db.collection.findOne() può risultare utile per visualizzare qual è in generale la struttura dei documenti contenuti in una collezione. Un po’ come facciamo in SQL con DESCRIBE table.

Infine per rimuovere un database occorre eseguire db.dropDatabase().

hotel> db.dropDatabase()
{ ok: 1, dropped: 'hotel' }

Con l’ultimo comando abbiamo rimosso il database. Se volessimo ripetere i passaggi visti in precedenza e ricreare il database e le collezioni velocemente possiamo avvalerci di un’altra funzionalità interessante di mongosh, ovvero la possibilità di visualizzare la cronologia dei comandi eseguiti. Basterà semplicemente premere il tasto freccia SU o freccia GIÙ.

Shell, Modalità editor ed estensione per VS Code

Come il linguaggio SQL (Structured Query Language), anche MongoDB Query Language (MQL) presenta una sintassi intuitiva, che tuttavia può risultare prolissa.

Interrogando un database, ci si accorge presto che può essere comodo strutturare le query su più righe per facilitarne la lettura.

Abbiamo già visto che mongosh consente di inserire i comandi una riga per volta finché la query non risulta completa. Tuttavia, ogni volta che andiamo a capo, possiamo solo editare la riga corrente.

Se ciò non fosse sufficiente, mongosh presenta anche 2 diverse modalità che garantiscono maggiore libertà nell’editare una query.

  • Con il comando edit è possibile aprire un editor esterno con il quale editare liberamente le query su più linee.
  • Con il comando .editor apriamo invece un semplice editor presente in mongosh in cui poter strutturare i comandi su più righe. Abbiamo però sempre il limite di poter editare solo la riga corrente.

Come dicevamo, per aprire l’editor interno basta eseguire .editor. Dopo aver inserito una query, basterà premere la combinazione di tasti Ctrl+D per eseguirla e ritornare al prompt di mongosh.

myDb> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)

Per usare il comando edit occorre invece selezionare un editor predefinito. Possiamo farlo in vari modi, per esempio definendo la variabile d’ambiente EDITOR, ma il metodo più semplice consiste nel scegliere l’editor direttamente in mongosh con il comando config.set('editor', 'percorso-editor'). Per esempio possiamo scegliere Vi come editor predefinito.

config.set('editor', 'vi')

Oppure, su Windows indichiamo Notepad come editor predefinito specificando il percorso corretto.

config.set('editor', 'C:\Windows\notepad.exe')

Ogni volta che eseguiamo il comando edit, verrà aperto un file con estensione .js che MongoDB salva all’interno di una cartella in cui sono presenti anche altri file di supporto. Su macOS, i file verranno salvati all’interno della cartella ~/.mongodb/mongosh/editor.

Per avviare una nuova sessione di modifica, basta digitare il comando edit senza alcun argomento. Verrà aperto un file in cui possiamo inserire i comandi che preferiamo. Una volta salvato il file, ritorneremo al prompt di mongosh.

Se al comando edit passiamo come argomento una variabile o un’altra istruzione, queste saranno usate come contenuto base del file da editare.

Shell integrata in MongoDB Compass

shell mongodb compass

Un’altra valida alternativa per lavorare in maniera ottimale con MongoDB consiste nell’usare la shell incorporata in MongoDB Compass.

Dopo aver effettuato l’accesso al server, MongoDB Compass mostrerà l’elenco dei database. Nella parte bassa dell’interfaccia è presente un pulsante per attivare la shell.

La shell di MongoDB Compass fornisce un sistema di autocompletamento e permette inoltre di scrivere delle istruzioni su più righe. Dopo aver completato la prima riga, sarà sufficiente premere la combinazione Shift + INVIO per spostarsi alla riga successiva. Inoltre, possiamo muoverci tranquillamente da una riga all’altra tramite i tasti freccia. Per completare un’operazione sarà sufficiente premere il tasto INVIO.

Estensione di VS Code

Vogliamo inoltre segnalare l’ estensione di MongoDB per VS Code con la quale possiamo collegarci ad un database da VS Code ed effettuare varie operazioni senza lasciare mai l’editor.

Presenta diverse funzionalità interessanti. Una di queste si chiama Playgrounds. Si tratta di uno spazio di lavoro in cui poter testare le query avendo libertà di editare ed organizzare i vari comandi su più righe e scegliere anche di eseguire solo un’operazione alla volta.

Eseguire degli script

Nel paragrafo precedente abbiamo visto che col comando edit viene aperto un nuovo file in cui inserire delle istruzioni da eseguire.

MongoDB offre anche la possibilità di caricare ed eseguire un qualsiasi file Javascript nell’ambiente della shell attraverso il comando load(path-to-file).

Per fare un esempio, creiamo una nuova cartella, spostiamoci al suo interno e lanciamo npm init -y (è necessario aver installato Node.js) per inizializzare un nuovo progetto.

mkdir mongodb-script-example && cd $_
npm init -y

Installiamo poi Faker col quale possiamo generare dati casuali come nomi, indirizzi, prezzi, email ecc…

npm install @faker-js/faker

Creiamo successivamente un nuovo file migrationUsers.js come quello mostrato sotto.

const { faker } = require('@faker-js/faker');

const NUM_OF_USERS = 10;

// equivalente al comando 'use ecommerce'
db.getSiblingDB('ecommerce'); 

// eliminiamo la collezione se presente
db.users.drop();

// creiamo una nuova collezione 'users'
db.createCollection('users');

// restituisce un oggetto con dati fittizi
const createUser = () => ({
  name: faker.name.findName(),
  email: faker.internet.email(),
  address: faker.address.streetAddress(),
  bio: faker.lorem.sentence(),
});

// creiamo un array di NUM_OF_USERS elementi
// in cui ogni elemento è un oggetto restituito
// dalla funzione createUser()
const users = Array.from({ length: NUM_OF_USERS }, createUser);

// inseriamo gli utenti nella collezione 'users'
// passando l'array a db.users.insertMany()
db.users.insertMany(users);

Nel frammento di codice riportato sopra, importiamo Faker e selezioniamo un nuovo database ecommerce. Bisogna fare attenzione perché in uno script non possiamo usare i comandi come use ecommerce in quanto non è codice Javascript valido. Dobbiamo invece avvalerci dei metodi equivalenti come db.getSiblingDB('ecommerce').

Potete trovare un elenco completo sulla documentazione ufficiale di MongoDB.

Nel nostro esempio abbiamo eliminato la collezione users nel caso fosse già presente per poi crearne una nuova.

Definiamo poi la funzione createUser() che restituisce un oggetto con dati fittizi.

Infine creiamo un array contenente NUM_OF_USERS elementi. Ciascun elemento è un oggetto con dati generati in maniera casuale. Terminiamo aggiungendo i dieci documenti alla collezione users invocando db.users.insertMany(users).

Per eseguire lo script, lanciamo mongosh all’interno della stessa cartella in cui si trova il file migrationUsers.js.

Una volta attivata la shell di MongoDB, invochiamo il comando load('migrationUsers.js').

A questo punto dovremmo avere un nuovo database ecommerce in cui è presente la collezione users con 10 documenti (db.users.countDocuments() restituisce il numero di documenti della collezione).

Eseguendo il comando db.users.findOne(), visualizzeremo uno dei documenti come quello riportato sotto.

{
  _id: ObjectId("622108d41f8575e55ec32ba4"),
  name: 'Clara Luettgen',
  email: '[email protected]',
  address: '529 Shanahan Branch',
  bio: 'Consequatur veritatis itaque odit optio optio fugit reprehenderit ex.'
}

Nella prossima lezione

Per questa lezione è tutto. Nella prossima vedremo in maggiore dettaglio come usare i metodi db.collection.insertOne() e db.collection.insertMany() per aggiungere dei documenti ad una collezione. Illustreremo poi come aggiornare le informazioni contenute in uno o più documenti attraverso i metodi db.collection.updateOne() e db.collection.updateMany().

Pubblicitร