Introducció

Les bases de dades documental emmagatzemen dades com a documents.

Document

A continuació tens un exemple d'un document JSON que descriu al empleat Laura:

{
    "_id": "laura",
    "firstName": "Laura",
    "lastName": "Codina",
    "email": "laura@acme.com",
    "department": "Finance"
}

Els documents de les bases de dades documental són autodescriptius , el que significa que contenen tant els valors de les dades com la informació sobre quin tipus de dades s'emmagatzemen.

A continuació tens un document d'un altre empleat que treballa en diversos departaments:

{
    "_id": "roser",
    "firstName": "Roser",
    "lastName": "Vilalta",
    "email": "roser@acme.com",
    "salary": 70000,
    "department": ["Finance", "Accounting"]
}

Aquest segon document té algunes diferències respecte al primer exemple.

A les bases de dades documentals, els documents no només es descriuen per si mateixos, sinó que també el seu esquema és dinàmic, la qual cosa significa que no cal definir-lo abans de començar a desar les dades. Els camps poden diferir entre diferents documents de la mateixa base de dades, i pots modificar l'estructura del document a voluntat, afegint o eliminant camps a mesura que avances. Els documents també es poden imbricar, és a dir, un camp d'un document pot tenir un valor que consisteix en un altre document, cosa que permet emmagatzemar dades complexes dins d'una única entrada de document.

{
    "_id": "david",
    "firstName": "David",
    "lastName": "de Mingo",
    "email": "david@acme.com",
    "department": ["Finance", "Accounting"],
    "socialMediaAccounts": [
        {
            "type": "facebook",
            "username": "david_de_mingo"
        },
        {
            "type": "twitter",
            "username": "@ddemingo"
        }
    ]
}

Entorn de treball

Instal.la MongoDB i el MongoDB Shell:

> scoop install main/mongodb extras/mongosh

Arrenca la base de dades:

> start-process -NoNewWindow mongodb.exe

Executa el shell:

> mongosh   
Current Mongosh Log ID: 6780f879bf517fb2d4cb0ce1
Connecting to:          mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.3.8
Using MongoDB:          8.0.4
Using Mongosh:          2.3.8

...
test>

El shell es connecta al desplegament de MongoDB que s'executa a localhost amb el port predeterminat 27017.

Això és equivalent a l'ordre següent:

> mongosh "mongodb://localhost:27017"

Pots verificar la teva connexió de base de dades actual utilitzant el mètode db.getMongo().

test> db.getMongo()
mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.3.8

El mètode retorna l'URI de l'string de connexió per a la teva connexió actual:

Bases de dades, col.leccions i documents

MongoDB emmagatzema la seva informació en documents, que es poden mostrar en format JSON (JavaScript Object Notation). Probablement us agradaria emmagatzemar diferents tipus de documents, com ara usuaris i comandes, en llocs separats. Això vol dir que MongoDB necessita una manera d'agrupar documents, de manera similar a una taula en un base de dades relacional. A MongoDB, això s'anomena col·lecció.

MongoDB divideix les col·leccions en bases de dades separades. A diferència de la sobrecàrrega habitual que produeixen les bases de dades al món SQL, les bases de dades de MongoDB són només espais de noms per distingir entre col·leccions. Per consultar MongoDB, haureu de conèixer la base de dades (o l'espai de noms) i la col·lecció que voleu consultar per als documents. Si no s'especifica cap altra base de dades a l'inici, el shell selecciona una base de dades per defecte anomenada test.

Per mostrar la base de dades que utilitzeu, escriu db:

> db
test

L'operació hauria de retornar test, que és la base de dades per defecte.

A continuació crea una base de dades nova per mantenir tots els exercicis de l'activitat en el mateix espai de noms:

test> use demo
switched to db demo
demo>

Veureu un missatge que verifica que heu canviat de base de dades.

És hora de crear el vostre primer document. Com que utilitzeu un shell de JavaScript, els vostres documents s'especificaran en JSON. Per exemple, un document senzill que descrigui un usuari podria semblar així:

{ name: "laura" }

El document conté una única clau i un valor per emmagatzemar el nom d'usuari de la Laura.

Insercions i consultes

Per desar aquest document, heu de triar una col·lecció on desar-lo. Prou adequadament, el desaràs a la col·lecció users.

demo> db.users.insertOne({name: "laura"})
{
  acknowledged: true,
  insertedId: ObjectId('678171de72c54e457acb0ce2')
}

Si no existeix una col·lecció, MongoDB la crea la primera vegada que emmagatzemeu les dades d'aquesta col·lecció.

Si la inserció té èxit, acabeu de desar el vostre primer document.

Podeu fer una consulta per veure el nou document:

demo> db.users.find()
[ { _id: ObjectId('678171de72c54e457acb0ce2'), name: 'laura' } ]

Tanca la connexió amb exit o quit.

demo> exit

Torna a l'altre terminal para la base de dades MongoDB, i torna a arrencar la base de dades.

Torna a connectar-te a la base de dades.

Com que les dades ara formen part de la col·lecció users, tornar a obrir l'intèrpret d'ordres i executar la consulta mostrarà el mateix resultat:

test> use demo
switched to db demo
demo> db.users.find()
[ { _id: ObjectId('678171de72c54e457acb0ce2'), name: 'laura' } ]

_ID FIELDS

Tingueu en compte que s'ha afegit un camp _id al document. Podeu pensar en el valor _id com a clau primària del document. Cada document de MongoDB requereix un _id, i si no n'hi ha cap quan es crea el document, es generarà un ObjectID i s'afegirà al document en aquest moment.

L'ObjectID que apareix al teu shell no serà el mateix que el de la llista de codi, però serà únic entre tots els valors _id de la col·lecció, que és l'únic requisit per al camp. Podeu establir el vostre propi _id establint-lo al document que inseriu, l'ObjectID és només el predeterminat de MongoDB

Afegeix un nou usuari a la col.lecció:

demo> db.users.insertOne({name: "david"})
{
  acknowledged: true,
  insertedId: ObjectId('6781722272c54e457acb0ce3')
}

Ara hi hauria d'haver dos documents a la col·lecció. Continueu i comproveu-ho executant l'ordre count:

demo> db.users.countDocuments()
2

Predicat de consulta

Ara que teniu més d'un document a la col·lecció, mirem algunes consultes una mica més sofisticades. Com abans, encara podeu consultar tots els documents de la col·lecció:

demo> db.users.find()
[
  { _id: ObjectId('678171de72c54e457acb0ce2'), name: 'laura' },
  { _id: ObjectId('6781722272c54e457acb0ce3'), name: 'david' }
]

També podeu passar un senzill selector de consultes al mètode find. Un selector de consultes és un document que s'utilitza per fer coincidir tots els documents de la col·lecció. Per consultar tots els documents on el nom d'usuari és laura, passeu un document senzill que actua com a selector de consultes com aquest:

demo> db.users.find({name:"laura"})
[ { _id: ObjectId('678171de72c54e457acb0ce2'), name: 'laura' } ]

El predicat de consulta {username: "laura"} retorna tots els documents on username és laura.

Tingueu en compte que cridar el mètode find sense cap argument és equivalent a passar un predicat buit: db.users.find() és el mateix que db.users.find({}).

A continuació, afegeix alguns usuaris més amb insertMany:

demo> db.users.insertMany([
... {name:"laura", age: 34},
... {name:"roser", email: "roser@gmail.com"}
... ])
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('678172be72c54e457acb0ce4'),
    '1': ObjectId('678172be72c54e457acb0ce5')
  }
}

El shell de MongoDB afegeix els tres punts després de la primera línia de la consulta per indicar que l'ordre pren més d'una línia.

També pots especificar diversos camps al predicat de consulta, que crea un AND implícit entre els camps.

Per exemple, consulteu amb el selector següent:

demo> db.users.find({name:"laura", age:34})
[
  { _id: ObjectId('678172be72c54e457acb0ce4'), name: 'laura', age: 34 }
]

La consulta torna tots els documents en que name és igual a "laura" i age és igual a 34.

També pots utilitzar l'operador $and de manera explícita. La consulta anterior és idèntica a:

demo> db.users.find({ $and: [{name:"laura",age:34}] })
[
  { _id: ObjectId('678172be72c54e457acb0ce4'), name: 'laura', age: 34 }
]

La selecció de documents amb un OR és similar: només cal que utilitzeu l'operador $or.

Considereu la consulta següent:

demo> db.users.find({ $or: [ {name: "david"}, {age: 34} ] })
[
  { _id: ObjectId('6781722272c54e457acb0ce3'), name: 'david' },
  { _id: ObjectId('678172be72c54e457acb0ce4'), name: 'laura', age: 34 }
]

La consulta retorna els documents david i laura, perquè hem demanat un nom david o una edat de 34.

Aquest exemple és diferent dels anteriors, perquè no només insereix o cerca un document concret. Més aviat, la consulta en si és un document. La idea de representar les ordres com a documents s'utilitza sovint a MongoDB i pot sorprendre si esteu acostumats a les bases de dades relacionals. Un dels avantatges d'aquesta interfície és que és més fàcil crear consultes amb programació a la vostra aplicació perquè són documents en lloc d'una string SQL llarg.

Actualitzar un documents

Totes les actualitzacions requereixen almenys dos arguments. El primer especifica quins documents cal actualitzar i el segon defineix com s'han de modificar els documents seleccionats. Els primers exemples mostren la modificació d'un sol document, però les mateixes operacions es poden aplicar a molts documents, fins i tot a una col·lecció sencera, tal com mostrem al final d'aquesta secció. Però tingueu en compte que per defecte el mètode update() actualitza un sol document.

Hi ha dos tipus generals d'actualitzacions, amb propietats i casos d'ús diferents. Un tipus d'actualització implica aplicar operacions de modificació a un document o documents, i l'altre tipus implica substituir el document antic per un de nou.

Modificar

El primer tipus d'actualització implica passar un document amb algun tipus de descripció de l'operador com a segon argument a la funció d'actualització.

En aquesta secció, veureu un exemple de com utilitzar l'operador $set, que estableix un sol camp amb el valor especificat. Suposem que l'usuari David decideix afegir el seu país de residència.

Amb updateOne pots modificar un document:

demo> db.users.updateOne({name:"david"}, {$set: {country: "Spain"}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

Aquesta actualització indica a MongoDB que trobi un document on el nom d'usuari sigui "david" i que, a continuació, estableixi el valor de la propietat del country a Spain . Veu que el canvi es reflecteix al missatge que el servidor envia de tornada (modifiedCount: 1).

Si ara fas una consulta, pots veure que el document s'ha actualitzat:

demo> db.users.find({name:"david"})
[
  {
    _id: ObjectId('6781722272c54e457acb0ce3'),
    name: 'david',
    country: 'Spain'
  }
]

A continuació actualitzem el pais de residencia de la laura:

demo> db.users.updateOne({name:"laura"}, {$set: {country: "Spain"}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
demo> db.users.find({name:"laura"})
[
  {
    _id: ObjectId('678171de72c54e457acb0ce2'),
    name: 'laura',
    country: 'Spain'
  },
  { _id: ObjectId('678172be72c54e457acb0ce4'), name: 'laura', age: 34 }
]

El mètode updateOne només actuatliza el primer document que troba.

Si tornes a repetir l'operació pots veure que no passa res:

demo> db.users.updateOne({name:"laura"}, {$set: {country: "Spain"}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 0,
  upsertedCount: 0
}

Pots veure que s'ha trobat un document matchedCount: 1, però que no s'ha modificat modifiedCount: 0.

Si vols actualitzar totes les laures a la vegada ho pots fer amb el mètode updateMany, però enlloc d'això actuatlitazarem només la laura que té 34 anys:

demo> db.users.updateOne({name:"laura", age: 34}, {$set: {country: "Spain"}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
demo> db.users.find({name:"laura"})
[
  {
    _id: ObjectId('678171de72c54e457acb0ce2'),
    name: 'laura',
    country: 'Spain'
  },
  {
    _id: ObjectId('678172be72c54e457acb0ce4'),
    name: 'laura',
    age: 34,
    country: 'Spain'
  }
]

Dades complexes

Els documents poden contenir estructures de dades complexes.

Suposem que, a més d'emmagatzemar la informació del perfil, els usuaris poden emmagatzemar llistes de les seves coses preferides.

Un exemple de document podria ser aquest:

{
  name: "roser",
  favorites: {
    cities: ["Barcelona", "Girona"],
    movies: ["Forrest Gump", "The Godfather", "Titanic"]
  }
}

La clau favorites apunta a un objecte que conté dues claus més, que apunten a llistes de ciutats i pel·lícules preferides. Tenint en compte el que ja sabeu, podeu pensar en una manera de modificar el document original de la roser?

demo> db.users.updateOne({name: "roser"}, {$set: {
... favorites: {
...   cities: ["Barcelona","Girona"],
...   movies: ["Forrest Gump", "The Godfather", "Titanic"]
... }}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

Tingueu en compte que l'ús de l'espaiat per al sagnat no és obligatori, però ajuda a evitar errors, ja que el document és més llegible d'aquesta manera.

Modific david de la mateixa manera, però en aquest cas només afegireu un parell de pel·lícules preferides:

demo> db.users.updateOne({ name: "david" }, { $set: { favorites: { movies: ["Forrest Gump", "Life of Brian"] }}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

Si cometeu una errada, podeu utilitzar la tecla de fletxa amunt per recordar l'última declaració de l'intèrpret d'ordres.

Ara consulteu la col·lecció users per assegurar-vos que ambdues actualitzacions han tingut èxit:

demo> db.users.find()
[
...
  {
    _id: ObjectId('678172be72c54e457acb0ce5'),
    name: 'roser',
    email: 'roser@gmail.com',
    favorites: {
      cities: [ 'Barcelona', 'Girona' ],
      movies: [ 'Forrest Gump', 'The Godfather', 'Titanic' ]
    }
  }
]

En sentit estricte, el mètode find() retorna un cursor als documents que retornen. Per tant, per accedir als documents haureu d'iterarel cursor. El mètode find() retorna automàticament 20 documents (si estan disponibles) després d'iterar el cursor 20 vegades.

A continució consulta tots el usuaris als qui els hi agrada la pel.lícula Forrest Gump:

demo> db.users.find({"favorites.movies": "Forrest Gump"})
[
  {
    _id: ObjectId('6781722272c54e457acb0ce3'),
    name: 'david',
    country: 'Spain',
    favorites: { movies: [ 'Forrest Gump', 'Life of Brian' ] }
  },
  {
    _id: ObjectId('678172be72c54e457acb0ce5'),
    name: 'roser',
    email: 'roser@gmail.com',
    favorites: {
      cities: [ 'Barcelona', 'Girona' ],
      movies: [ 'Forrest Gump', 'The Godfather', 'Titanic' ]
    }
  }
]

El punt entre favorites i movies indica al motor de consultes que cerqui una clau anomenada favorites que apunti a un objecte amb una clau interna anomenada movies i després que coincideixi amb el valor de la clau interna. Per tant, aquesta consulta retornarà els dos documents d'usuari perquè les consultes a les llistes coincideixen si algun element de la llista coincideix amb la consulta original

Add to set

Suposem que sabeu que a qualsevol usuari que li agradi Forrest Gump també li agrada Pulp Ficton i que voleu actualitzar la vostra base de dades per reflectir aquest fet.

Com que tot el que voleu fer és afegir un element a la llista, és millor que utilitzeu $push o $addToSet. Els dos operadors afegeixen un element a una llista, però el segon ho fa de manera única, evitant una addició duplicada.

demo> db.users.updateMany( {"favorites.movies": "Forrest Gump"},
... { $addToSet: {"favorites.movies": "Pulp Fiction"}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 2,
  modifiedCount: 2,
  upsertedCount: 0
}

El primer argument és un predicat de consulta que coincideix amb els usuaris que tenen Forrest Gump a la seva llista de pel·lícules. El segon argument afegeix Pulp Fiction a aquesta llista mitjançant l'operador $addToSet.

Esborrant dades

Per eliminar només un determinat subconjunt dels documents d'una col·lecció pots passar un selector de consultes al mètode remove().

Si vola eliminar tots els usuaris la ciutat preferida dels quals és Girona, l'expressió és senzilla:

demo> db.users.deleteOne({"favorites.cities": "Barcelona"})
{ acknowledged: true, deletedCount: 1 }

Si vols eliminar tots els documents d'una col.lecció:

demo> db.users.deleteMany({})
{ acknowledged: true, deletedCount: 3 }

Tingues en compte que l'operació deleteMany({}) en realitat no elimina la col·lecció; només elimina documents d'una col·lecció.

Si la vostra intenció és suprimir la col·lecció juntament amb tots els seus índexs, utilitzeu el mètode drop():

demo> db.users.drop()
true

Altres característiques del shell

És possible que ja ho hàgiu notat, però le shell fa moltes coses per facilitar el treball amb MongoDB. Podeu tornar a visitar les ordres anteriors fent servir les fletxes amunt i avall i utilitzar l'emplenament automàtic per a determinades entrades, com ara els noms de les col·leccions. La funció d'emplenament automàtic utilitza la tecla de tabulació per emplenar automàticament o per llistar les possibilitats de finalització.

També podeu descobrir més informació a l'intèrpret d'ordres escrivint això:

> help

Moltes funcions imprimeixen missatges d'ajuda que també els expliquen. Prova-ho:

demo> db.help()

  Database Class:

    getMongo                                   Returns the current database connection
    getName                                    Returns the name of the DB
...

demo> db.getName()
demo

També hi ha diverses opcions que podeu utilitzar quan inicieu l'intèrpret d'ordres de MongoDB. Per mostrar una llista d'aquests, afegiu el flag d'ajuda al arrencar el shell:

> mongo --help

Índexs

És habitual crear índexs per millorar el rendiment de les consultes. Afortunadament, els índexs de MongoDB es poden crear fàcilment des del shell.

Un exemple d'indexació només té sentit si teniu una col·lecció amb molts documents.

Per tant, afegireu 20.000 documents senzills a una col·lecció de números. Com que el shell de MongoDB també és un intèrpret de JavaScript, el codi per aconseguir-ho és senzill:

demo> for (i=0; i < 20000; i++) { db.numbers.insertOne({num:i}) }
{
  acknowledged: true,
  insertedId: ObjectId('6782894472c54e457acb5b06')
}

Són molts documents, així que no us sorpreneu si la inserció triga uns quants segons a completar-se. Un cop torni, podeu executar un parell de consultes per verificar que tots els documents estan presents:

demo> db.numbers.countDocuments()
20000
demo> db.numbers.find()
[
  { _id: ObjectId('6782893c72c54e457acb0ce7'), num: 0 },
  { _id: ObjectId('6782893c72c54e457acb0ce8'), num: 1 },
  { _id: ObjectId('6782893c72c54e457acb0ce9'), num: 2 },
  { _id: ObjectId('6782893c72c54e457acb0cea'), num: 3 },
  { _id: ObjectId('6782893c72c54e457acb0ceb'), num: 4 },
  { _id: ObjectId('6782893c72c54e457acb0cec'), num: 5 },
  { _id: ObjectId('6782893c72c54e457acb0ced'), num: 6 },
  { _id: ObjectId('6782893c72c54e457acb0cee'), num: 7 },
  { _id: ObjectId('6782893c72c54e457acb0cef'), num: 8 },
  { _id: ObjectId('6782893c72c54e457acb0cf0'), num: 9 },
  { _id: ObjectId('6782893c72c54e457acb0cf1'), num: 10 },
  { _id: ObjectId('6782893c72c54e457acb0cf2'), num: 11 },
  { _id: ObjectId('6782893c72c54e457acb0cf3'), num: 12 },
  { _id: ObjectId('6782893c72c54e457acb0cf4'), num: 13 },
  { _id: ObjectId('6782893c72c54e457acb0cf5'), num: 14 },
  { _id: ObjectId('6782893c72c54e457acb0cf6'), num: 15 },
  { _id: ObjectId('6782893c72c54e457acb0cf7'), num: 16 },
  { _id: ObjectId('6782893c72c54e457acb0cf8'), num: 17 },
  { _id: ObjectId('6782893c72c54e457acb0cf9'), num: 18 },
  { _id: ObjectId('6782893c72c54e457acb0cfa'), num: 19 }
]
Type "it" for more

El mètode countDocuments() mostra que heu inserit 20.000 documents. La consulta posterior mostra els primers 20 resultats (aquest número pot ser diferent al vostre shell).

Podeu mostrar resultats addicionals amb la funció it:

demo> it
[
  { _id: ObjectId('6782893c72c54e457acb0cfb'), num: 20 },
  { _id: ObjectId('6782893c72c54e457acb0cfc'), num: 21 },
...

La funció it indica al shell que retorni el següent conjunt de resultats.

A continuació fes una consulta:

demo> db.numbers.find({num:500})
[ { _id: ObjectId('6782893c72c54e457acb0edb'), num: 500 } ]

Intervals

També pots fet consultes d'interval mitjançant els operadors especials $gt i $lt que representen major que i menys que, respectivament.

A continuació consulta tots els documents amb un valor numérico superior a 19995:

demo> db.numbers.find({num: {"$gt": 19995}})
[
  { _id: ObjectId('6782894472c54e457acb5b03'), num: 19996 },
  { _id: ObjectId('6782894472c54e457acb5b04'), num: 19997 },
  { _id: ObjectId('6782894472c54e457acb5b05'), num: 19998 },
  { _id: ObjectId('6782894472c54e457acb5b06'), num: 19999 }
]

També pots combinar els dos operadors per especificar els límits superior i inferior:

demo> db.numbers.find({num: {$gt: 20, $lt: 25}})
[
  { _id: ObjectId('6782893c72c54e457acb0cfc'), num: 21 },
  { _id: ObjectId('6782893c72c54e457acb0cfd'), num: 22 },
  { _id: ObjectId('6782893c72c54e457acb0cfe'), num: 23 },
  { _id: ObjectId('6782893c72c54e457acb0cff'), num: 24 }
]

Podeu veure que utilitzant un document JSON senzill, podeu especificar una consulta d'interval de la mateixa manera que ho faríeu a SQL. $gt i $lt són només dos d'una sèrie d'operadors que integren el llenguatge de consulta MongoDB. Altres inclouen $gte per a major o igual a, $lte per (ho heu endevinat) menor o igual a i $ne per no igual a.

Per descomptat, consultes com aquesta tenen poc valor tret que també siguin eficients:

Explain

Quan una base de dades rep una consulta, ha de planificar com executar-la; això s'anomena pla de consultes.

explain descriu els camins de consulta i permet als desenvolupadors diagnosticar operacions lentes determinant quins índexs ha utilitzat una consulta. Sovint, una consulta es pot executar de diverses maneres i, de vegades, això provoca un comportament que potser no espereu.

demo> db.numbers.find({num: {"$gt": 19995}}).explain("executionStats")
{
  explainVersion: '1',
  queryPlanner: {
    namespace: 'demo.numbers',
    parsedQuery: { num: { '$gt': 19995 } },
    ...
  executionStats: {
    executionSuccess: true,
    nReturned: 4,
    executionTimeMillis: 4,
    totalKeysExamined: 0,
    totalDocsExamined: 20000,

La paraula clau "executionStats" sol·licita un mode diferent que ofereix una sortida més detallada:

Després d'examinar la sortida d'explain(), us sorprendrà veure que el motor de consultes ha d'escanejar tota la col·lecció, els 20.000 documents (totalDocsExamined), per retornar només quatre resultats (nReturned). El valor del camp totalKeysExamined mostra el nombre d'entrades d'índex escanejades, que és zero. Una diferència tan gran entre el nombre de documents escanejats i el nombre retornat marca això com una consulta ineficient.

En una situació del món real, on la col·lecció i els mateixos documents probablement serien més grans, el temps necessari per processar la consulta seria substancialment més gran que els 4 mil·lisegons (`executionTimeInMillis) indicats aquí (això pot ser diferent a la vostra màquina).

El que necessita aquesta col·lecció és un índex. Podeu crear un índex per a la clau num dels documents mitjançant el mètode createIndex():

demo> db.numbers.createIndex({num: 1})
num_1

Pots verure que passes un document al mètode createIndex() per definir les claus de l'índex. En aquest cas, el document {num: 1} indica que s'ha de crear un índex ascendent a la clau num per a tots els documents de la col·lecció numbers.

Pots verificar que l'índex s'ha creat invocant al mètode getIndexes():

demo> db.numbers.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { num: 1 }, name: 'num_1' }
]

La col·lecció té ara dos índexs. El primer és l'índex estàndard _id que es crea automàticament per a cada col·lecció; el segon és l'índex que heu creat a num. Els índexs d'aquests camps s'anomenen _id i num_1, respectivament. Si no proporcioneu un nom, MongoDB estableix automàticament noms significatius.

Si executeu la vostra consulta amb el mètode explain(), ara veureu la gran diferència en el temps de resposta de la consulta, tal com es mostra a la llista següent:

demo> db.numbers.find({num: {"$gt": 19995}}).explain("executionStats")
{
    ...
  executionStats: {
    executionSuccess: true,
    nReturned: 4,
    executionTimeMillis: 1,
    totalKeysExamined: 4,
    totalDocsExamined: 4,
    ...

Ara que la consulta utilitza l'índex num_1 a num, només escaneja els quatre documents relacionats amb la consulta. Això redueix el temps total per atendre la consulta de 4 ms a 1 ms!

Els índexs no són gratuïts; ocupen una mica d'espai i poden fer que les vostres insercions siguin una mica més cares, però són una eina essencial per a l'optimització de consultes.

Administració

Informació de la base de dades

Sovint voldreu saber quines col·leccions i bases de dades existeixen en una instal·lació determinada. Afortunadament, l'intèrpret d'ordres de MongoDB proporciona una sèrie d'ordres, juntament amb una mica de sucre sintàctic, per obtenir informació sobre el sistema.

show dbs imprimeix una llista de totes les bases de dades del sistema:

demo> show dbs
admin    40.00 KiB
config  108.00 KiB
demo    672.00 KiB
local    72.00 KiB

show collections mostra una llista de totes les col·leccions definides a la base de dades actual.

demo> show collections
numbers

Per obtenir una visió de nivell inferior sobre bases de dades i col·leccions, el mètode stats() resulta útil. Quan l'executeu en un objecte de base de dades, obtindreu la següent sortida:

demo> db.stats()
{
  db: 'demo',
  collections: Long('1'),
  views: Long('0'),
  objects: Long('20000'),
  avgObjSize: 31,
  dataSize: 620000,
  storageSize: 237568,
  indexes: Long('2'),
  indexSize: 409600,
  totalSize: 647168,
  scaleFactor: Long('1'),
  fsUsedSize: 317962870784,
  fsTotalSize: 510735151104,
  ok: 1
}

També podeu executar l'ordre stats() en una col·lecció individual:

demo> db.numbers.stats()
{
  ok: 1,
  capped: false,

Alguns dels valors proporcionats en aquests documents de resultats només són útils en situacions complicades de depuració o d'ajust. Però, com a mínim, podreu esbrinar quant d'espai ocupa una col·lecció determinada i els seus índexs.

Compass

Compass és una eina interactiva per consultar, optimitzar i analitzar les vostres dades de MongoDB.

Instal.la:

> scoop install extras/mongodb-compass

Dades de mostra

Descarrega el conjunt de dades de mostra complet:

> curl https://atlas-education.s3.amazonaws.com/sampledata.archive -o sampledata.archive

Instal.la les eines d'administració:

> scoop install main/mongodb-database-tools

Executa mongorestore per desempaquetar i allotjar una còpia local del conjunt de dades de mostra (la base de dades ha d'estar arrencada):

> mongorestore --archive=sampledata.archive
> rm .\sampledata.archive

TODO