Afhankelijk van de eisen die je aan je software stelt, zou je prioriteit kunnen geven aan flexibiliteit, schaalbaarheid, prestaties of snelheid. Daarom vinden developers en bedrijven het vaak lastig om een database te kiezen die past bij hun behoeften. Als je een database nodig hebt die hoge flexibiliteit en schaalbaarheid biedt, en gegevensaggregatie voor client-analyse, dan is MongoDB misschien de juiste keuze voor jou!

In dit artikel bespreken we de structuur van de MongoDB database en hoe je je database maakt, monitort en beheert! Laten we beginnen.

Hoe is een MongoDB database gestructureerd?

MongoDB is een schemaloze NoSQL database. Dit betekent dat je geen structuur specificeert voor de tabellen/databases zoals je doet voor SQL databases.

Wist je dat NoSQL databases eigenlijk sneller zijn dan relationele databases? Dat komt door eigenschappen als indexering, sharding en aggregatiepijplijnen. MongoDB staat ook bekend om zijn snelle query-uitvoering. Daarom geniet het de voorkeur van bedrijven als Google, Toyota en Forbes.

Hieronder verkennen we enkele belangrijke kenmerken van MongoDB.

Documenten

MongoDB heeft een documentdatamodel dat gegevens opslaat als JSON documenten. De documenten komen op natuurlijke wijze overeen met de objecten in de code van de applicatie, waardoor het voor ontwikkelaars eenvoudiger te gebruiken is.

In een relationele databasetabel moet je een kolom toevoegen om een nieuw veld toe te voegen. Dat is niet het geval met velden in een JSON document. Velden in een JSON document kunnen per document verschillen, zodat ze niet aan elk record in de database worden toegevoegd.

Documenten kunnen structuren opslaan zoals arrays die genest kunnen worden om hiërarchische relaties uit te drukken. Bovendien zet MongoDB documenten om in een binair JSON (BSON) type. Dit zorgt voor snellere toegang en meer ondersteuning voor verschillende gegevenstypen zoals string, integer, boolean getal, en nog veel meer!

Replicasets

Wanneer je in MongoDB een nieuwe database aanmaakt, maakt het systeem automatisch nog minstens 2 kopieën van je gegevens. Deze kopieën staan bekend als “replicasets,” en ze repliceren voortdurend gegevens tussen deze kopieën, waardoor de beschikbaarheid van je gegevens wordt verbeterd. Ze bieden ook bescherming tegen downtime tijdens een systeemstoring of gepland onderhoud.

Collecties

Een collectie is een groep documenten die aan één database zijn gekoppeld. Ze zijn vergelijkbaar met tabellen in relationele databases.

Collecties zijn echter veel flexibeler. Ten eerste zijn ze niet afhankelijk van een schema. Ten tweede hoeven de documenten niet van hetzelfde gegevenstype te zijn!

Om een lijst te zien van de collecties die bij een database horen, gebruik je het commando listCollections.

Aggregatiepijplijnen

Je kunt dit framework gebruiken om verschillende operators en expressions samen te voegen. Het is flexibel omdat je hiermee gegevens van elke structuur kunt verwerken, transformeren en analyseren.

Hierdoor maakt MongoDB snelle gegevensstromen en features mogelijk over 150 operatoren en expressies. Het heeft ook verschillende stadia, zoals het stadium Union, dat flexibel resultaten van meerdere collecties samenvoegt.

Indexering

Je kunt elk veld in een MongoDB document indexeren om de efficiëntie ervan te verhogen en de querysnelheid te verbeteren. Indexeren bespaart tijd door de index te scannen om de geïnspecteerde documenten te beperken. Is dit niet veel beter dan elk document in de collectie te lezen?

Je kunt verschillende indexeringsstrategieën gebruiken, waaronder samengestelde indexen van meerdere velden. Stel bijvoorbeeld dat je verschillende documenten hebt met de voor- en achternaam van de werknemer in afzonderlijke velden. Als je wilt dat de voor- en achternaam terugkomen, kun je een index maken die zowel “Achternaam” als “Voornaam” bevat. Dit is veel beter dan een index op “Achternaam” en een andere op “Voornaam”.

Je kunt tools als Performance Advisor gebruiken om verder te begrijpen welke query baat kan hebben bij indexering.

Sharding

Sharding verdeelt een enkele dataset over meerdere databases. Die dataset kan dan op meerdere machines worden opgeslagen om de totale opslagcapaciteit van een systeem te vergroten. Dit komt omdat het grotere datasets opdeelt in kleinere brokken en deze opslaat in verschillende datanodes.

MongoDB deelt gegevens op collectieniveau en verdeelt de documenten in een collectie over de shards in een cluster. Dit zorgt voor schaalbaarheid doordat de architectuur de grootste applicaties aankan.

Een MongoDB database aanmaken

Je moet eerst het juiste MongoDB pakket installeren dat geschikt is voor jouw OS. Ga naar de pagina ‘Download MongoDB Community Server‘. Kies uit de beschikbare opties: de laatste “version”, “package” format als zip bestand, en “platform” als je OS en klik op “Download” zoals hieronder afgebeeld:

Deze afbeelding toont de beschikbare opties: versie, platform en pakket tijdens het downloaden van MongoDB Community Server.
MongoDB community server downloadproces. (Beeldbron: MongoDB Community Server)

Het proces is vrij eenvoudig, dus je zult MongoDB in een mum van tijd op je systeem geïnstalleerd hebben staan!

Zodra je de installatie hebt gedaan, open je je commandoprompt en typ je mongod -version in om het te verifiëren. Als je niet de volgende uitvoer krijgt en in plaats daarvan een reeks fouten ziet, moet je misschien opnieuw installeren:

Dit is een codefragment om de MongoDB versie te checken na installatie.
Verifiëren van de MongoDB versie. (Bron afbeelding: configserverfirewall)

MongoDB Shell gebruiken

Voordat we beginnen, moet je ervoor zorgen dat:

  • Je client Transport Layer Security heeft en staat op je IP allowlist.
  • Je een gebruikersaccount en wachtwoord hebt op het gewenste MongoDB cluster.
  • Je MongoDB op je apparaat hebt geïnstalleerd.

Stap 1: Krijg toegang tot de MongoDB Shell

Start de MongoDB server door de instructies van elk besturingssysteem te volgen. Voor Windows typ je het volgende commando. Raadpleeg de MongoDB documentatie voor andere besturingssystemen.

net start MongoDB

Dit zou de volgende uitvoer moeten geven:

Dit is een codefragment om de MongoDB server te initialiseren
MongoDB server starten. (Beeldbron: c-sharpcorner)

Het vorige commando initialiseerde de MongoDB server. Om het uit te voeren moeten we in de commandoprompt mongo intikken.

Dit is een codefragment om de MongoDB server uit te voeren.
MongoDB shell uitvoeren. (Beeldbron: bmc)

Hier in de MongoDB shell kunnen we commando’s uitvoeren om databases te maken, gegevens in te voegen, gegevens te bewerken, administratieve commando’s te geven en gegevens te verwijderen.

Stap 2: Creëer je database

In tegenstelling tot gewone relationele databases heeft MongoDB geen commando om een database aan te maken. In plaats daarvan is er een sleutelwoord genaamd use dat overschakelt naar een opgegeven database. Als de database niet bestaat, wordt er een nieuwe database aangemaakt, anders wordt er gelinkt naar de bestaande database.

Om bijvoorbeeld een database genaamd “company” te starten, typ je in:

use Company
Dit is een codefragment om een database te maken in MongoDB.
Database aanmaken in MongoDB.

Je kunt db intypen om de zojuist aangemaakte database in je systeem te bevestigen. Als de nieuwe database die je hebt aangemaakt opduikt, heb je er met succes verbinding mee gemaakt.

Als je de bestaande databases wilt controleren, typ dan in show dbs en het geeft alle databases in je systeem terug:

Dit is een codefragment om de bestaande databases in het systeem te bekijken.
Het bekijken van databases in MongoDB.

Standaard maakt de installatie van MongoDB de admin, config, en lokale databases aan.

Is het je opgevallen dat de database die we hebben aangemaakt niet wordt weergegeven? Dat komt omdat we nog geen waarden in de database hebben opgeslagen! We zullen het invoegen bespreken in het gedeelte over databasebeheer.

Atlas UI gebruiken

Je kunt ook aan de slag met de databaseservice van MongoDB, Atlas. Hoewel je misschien moet betalen om toegang te krijgen tot sommige features van Atlas, zijn de meeste databasefuncties beschikbaar met het gratis niveau. De features van het gratis niveau zijn meer dan voldoende om een MongoDB database te maken.

Voordat we beginnen, zorg ervoor dat:

  1. Je IP op de allowlist staat .
  2. Je een gebruikersaccount en wachtwoord hebt op het MongoDB cluster dat je wilt gebruiken.

Om een MongoDB database met AtlasUI te maken, open je een browservenster en log je in op https://cloud.mongodb.com. Klik op de pagina van je cluster op Browse Collections. Als er geen databases in het cluster zijn, kun je je database aanmaken door te klikken op de knop Add My Own Data.

De prompt zal je vragen een database en een collectienaam op te geven. Als je die een naam hebt gegeven, klik je op Create, en je bent klaar! Je kunt nu nieuwe documenten invoeren of verbinding maken met de database met behulp van drivers.

Je MongoDB database beheren

In dit deel bespreken we een paar handige manieren om je MongoDB database effectief te beheren. Je kunt dit doen door het MongoDB Compass te gebruiken of door middel van collecties.

Collecties gebruiken

Terwijl relationele databases beschikken over goed gedefinieerde tabellen met gespecificeerde gegevenstypen en kolommen, heeft NoSQL collecties in plaats van tabellen. Deze collecties hebben geen structuur, en documenten kunnen variëren — je kunt verschillende gegevenstypen en velden hebben zonder dat het format van een ander document in dezelfde collectie moet overeenkomen.

Laten we ter demonstratie een collectie genaamd “Employee” maken en er een document aan toevoegen:

db.Employee.insert(
  {
   	"Employeename" : "Chris",
   	"EmployeeDepartment" : "Sales"
  }
)

Als het invoegen succesvol is, wordt WriteResult({ "nInserted" : 1 }) geretourneerd:

Dit codefragment retourneert WriteResult({
Succesvol invoegen in MongoDB.

Hier verwijst “db” naar de momenteel verbonden database. “Employee” is de nieuw aangemaakte collectie in de bedrijfsdatabase.

We hebben hier geen primaire sleutel ingesteld omdat MongoDB automatisch een primair sleutelveld genaamd “_id” aanmaakt en er een standaardwaarde op zet.

Voer het onderstaande commando uit om de collectie in JSON format te bekijken:

db.Employee.find().forEach(printjson)

Uitvoer:

{
  "_id" : ObjectId("63151427a4dd187757d135b8"),
  "Employeename" : "Chris",
  "EmployeeDepartment" : "Sales"
}

Hoewel de “_id” waarde automatisch wordt toegekend, zou je de waarde van de standaard primaire sleutel kunnen veranderen. Deze keer voegen we een ander document in in de “Employee” database, met de “_id” waarde als “1”:

db.Employee.insert(
  {  
   	"_id" : 1,
   	"EmployeeName" : "Ava",
   	"EmployeeDepartment" : "Public Relations"
  }
)

Bij het uitvoeren van het commando db.Employee.find().forEach(printjson) krijgen we de volgende uitvoer:

De uitvoer toont de documenten in de collectie Employee samen met hun primaire sleutel
Documenten in de collectie met hun primaire sleutel.

In de bovenstaande uitvoer is de “_id” waarde voor “Ava” ingesteld op “1” in plaats van automatisch een waarde toegewezen te krijgen.

Nu we met succes waarden hebben toegevoegd aan de database, kunnen we controleren of deze opduikt onder de bestaande databases in ons systeem met het volgende commando:

show dbs
De output toont de collectie Employee in de bestaande databases in ons systeem.
De lijst met databases weergeven.

En voila! Je hebt met succes een database in je systeem aangemaakt!

Het MongoDB Compass gebruiken

Hoewel we met MongoDB servers kunnen werken vanuit de Mongo shell, kan het soms vervelend zijn. Je kunt dit vooral ervaren in een productieomgeving.

Er is echter een door MongoDB gemaakt kompastool (met de toepasselijke naam Compass) dat het gemakkelijker kan maken. Het heeft een betere GUI en toegevoegde functionaliteiten zoals datavisualisatie, prestatieprofilering en CRUD (create, read, update, delete) toegang tot gegevens, databases en collecties.

Je kunt de Compass IDE voor je OS downloaden en installeren met het eenvoudige proces.

Open vervolgens de applicatie en maak een verbinding met de server door de connection string te plakken. Als je die niet kunt vinden, kun je klikken op Fill in connection fields individually. Als je het poortnummer niet hebt veranderd tijdens de installatie van MongoDB, klik dan gewoon op de verbindingsknop, en je bent binnen! Voer anders gewoon de waarden in die je hebt ingesteld en klik op Connect.

Deze afbeelding toont het venster New Connection, waar je kunt kiezen om de connection URL te plakken.
Venster New Connection in MongoDB. (Beeldbron: mongodb)

Geef vervolgens de Hostnaam, Poort en Authenticatie op in het venster New Connection.

In MongoDB Compass kun je tegelijkertijd een database aanmaken en de eerste collectie ervan toevoegen. Hier zie je hoe je dat doet:

  1. Klik op Create Database om de prompt te openen.
  2. Voer de naam van de database en de eerste collectie in.
  3. Klik op Create Database.

Je kunt meer documenten in je database invoegen door op de naam van je database te klikken, en vervolgens op de naam van de collectie om het tabblad Documents te zien. Je kunt dan op de knop Add Data klikken om een of meer documenten in je collectie in te voegen.

Bij het toevoegen van je documenten kun je ze één voor één invoeren, of als meerdere documenten in een matrix. Als je meerdere documenten toevoegt, zorg er dan voor dat deze door komma’s gescheiden documenten tussen vierkante haken staan. Bijvoorbeeld:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] },
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] },
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] },
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] },
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] },
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Klik ten slotte op Insert om de documenten aan je collectie toe te voegen. Zo ziet de body van een document eruit:

{
  "StudentID" : 1
  "StudentName" : "JohnDoe"
}

Hier zijn de veldnamen “StudentID” en “StudentName”. De veldwaarden zijn respectievelijk “1” en “JohnDoe”.

Nuttige commando’s

Je kunt deze collecties beheren met commando’s voor rolbeheer en gebruikersbeheer.

Commando’s voor gebruikersbeheer

De MongoDB commando’s voor gebruikersbeheer bevatten commando’s die betrekking hebben op de gebruiker. Met deze commando’s kunnen we gebruikers aanmaken, bijwerken en verwijderen.

dropUser

Dit commando verwijdert een enkele gebruiker uit de opgegeven database. Hieronder staat de syntaxis:

db.dropUser(username, writeConcern)

Hier is username een verplicht veld dat de naam specificeert van de gebruiker die uit de database moet worden verwijderd. Het optionele veld writeConcern bevat het niveau van schrijfbezorgdheid voor de verwijderingsoperatie. Het niveau van schrijfconcern kan worden bepaald door het optionele veld writeConcern.

Voordat je een gebruiker met de rol userAdminAnyDatabase laat vallen, moet je ervoor zorgen dat er minstens één andere gebruiker is met gebruikersbeheerprivileges.

In dit voorbeeld laten we de gebruiker “user26” in de testdatabase vallen:

use test
db.dropUser("user26", {w: "majority", wtimeout: 4000})

Uitvoer:

> db.dropUser("user26", {w: "majority", wtimeout: 4000});
true
createUser

Dit commando maakt als volgt een nieuwe gebruiker aan voor de opgegeven database:

db.createUser(user, writeConcern)

Hier is user een verplicht veld dat het document met authenticatie- en toegangsinformatie over de aan te maken gebruiker bevat. Het optionele veld writeConcern bevat het niveau van write concern voor de aanmaakoperatie. Het niveau van write concern kan worden bepaald door het optionele veld, writeConcern.

createUser geeft een foutmelding voor een dubbele gebruiker als de gebruiker al bestaat in de database.

Je kunt als volgt een nieuwe gebruiker in de testdatabase aanmaken:

use test
db.createUser(
  {
    user: "user26",
    pwd: "myuser123",
    roles: [ "readWrite" ]  
  }
);

De uitvoer is als volgt:

Successfully added user: { "user" : "user26", "roles" : [ "readWrite", "dbAdmin" ] }
grantRolesToUser

Je kunt dit commando gebruiken om extra rollen aan een gebruiker toe te kennen. Om het te gebruiken moet je de volgende syntaxis in gedachten houden:

db.runCommand(
  {
    grantRolesToUser: "<user>",
    roles: [ <roles> ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

Je kunt zowel door de gebruiker gedefinieerde als ingebouwde rollen opgeven in de hierboven genoemde rollen. Als je een rol wilt opgeven die bestaat in dezelfde database waar grantRolesToUser draait, kun je de rol opgeven met een document, zoals hieronder vermeld:

{ role: "<role>", db: "<database>" }

Of je kunt de rol gewoon specificeren met de naam van de rol. Bijvoorbeeld:

"readWrite"

Als je de rol wilt specificeren die in een andere database aanwezig is, zul je de rol met een ander document moeten specificeren.

Om een rol op een database toe te kennen, heb je de actie grantRole nodig op de opgegeven database.

Hier is een voorbeeld om je een duidelijk beeld te geven. Neem bijvoorbeeld een gebruiker productUser00 in de productendatabase met de volgende rollen:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  }
]

De operatie grantRolesToUser geeft “productUser00” de rol readWrite in de voorraaddatabase en de write rol op de productdatabase:

use products
db.runCommand({
  grantRolesToUser: "productUser00",
  roles: [
    { role: "readWrite", db: "stock"},
    "read"
  ],
  writeConcern: { w: "majority" , wtimeout: 2000 }
})

De gebruiker productUser00 in de productendatabase bezit nu de volgende rollen:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  },
  {
    "role" : "readWrite",
    "db" : "stock"
  },
  {
    "role" : "read",
    "db" : "products"
  }
]
usersInfo

Je kunt het commando usersInfo gebruiken om informatie over een of meer gebruikers terug te geven. Dit is de syntaxis:

db.runCommand(
  {
    usersInfo: <various>,
    showCredentials: <Boolean>,
    showCustomData: <Boolean>,
    showPrivileges: <Boolean>,
    showAuthenticationRestrictions: <Boolean>,
    filter: <document>,
    comment: <any> 
  }
)
{ usersInfo: <various> }

Qua toegang kunnen gebruikers altijd hun eigen informatie bekijken. Om de informatie van een andere gebruiker te bekijken, moet de gebruiker die het commando uitvoert rechten hebben die de actie viewUser op de database van de andere gebruiker bevatten.

Bij het uitvoeren van het commando userInfo kun je de volgende informatie verkrijgen, afhankelijk van de opgegeven opties:

{
  "users" : [
    {
      "_id" : "<db>.<username>",
      "userId" : <UUID>, // Starting in MongoDB 4.0.9
      "user" : "<username>",
      "db" : "<db>",
      "mechanisms" : [ ... ],  // Starting in MongoDB 4.0
      "customData" : <document>,
      "roles" : [ ... ],
      "credentials": { ... }, // only if showCredentials: true
      "inheritedRoles" : [ ... ],  // only if showPrivileges: true or showAuthenticationRestrictions: true
      "inheritedPrivileges" : [ ... ], // only if showPrivileges: true or showAuthenticationRestrictions: true
      "inheritedAuthenticationRestrictions" : [ ] // only if showPrivileges: true or showAuthenticationRestrictions: true
      "authenticationRestrictions" : [ ... ] // only if showAuthenticationRestrictions: true
    },
  ],
  "ok" : 1
} 

Nu je het algemene idee hebt van wat je met het commando usersInfo kunt bereiken, is de voor de hand liggende volgende vraag die opkomt: welke commando’s zijn handig om specifieke gebruikers en meerdere gebruikers te bekijken?

Hier zijn twee handige voorbeelden om hetzelfde te illustreren:
Om de specifieke rechten en informatie voor specifieke gebruikers te bekijken, maar niet de referenties, voor een gebruiker “Anthony” gedefinieerd in de “office” database, voer je het volgende commando uit:

db.runCommand(
  {
    usersInfo:  { user: "Anthony", db: "office" },
    showPrivileges: true
  }
)

Als je een gebruiker in de huidige database wilt bekijken, kun je de gebruiker alleen bij naam noemen. Als je bijvoorbeeld in de home database bent en er bestaat een gebruiker met de naam “Timothy” in de home database, dan kun je het volgende commando uitvoeren:

db.getSiblingDB("home").runCommand(
  {
    usersInfo:  "Timothy",
    showPrivileges: true
  }
)

Vervolgens kun je een array gebruiken als je de informatie voor verschillende gebruikers wilt bekijken. Je kunt de optionele velden showCredentials en showPrivileges opnemen, of ze weglaten. Zo zou het commando er dan uitzien:

db.runCommand({
usersInfo: [ { user: "Anthony", db: "office" }, { user: "Timothy", db: "home" } ],
  showPrivileges: true
})
revokeRolesFromUser

Je kunt het commando revokeRolesFromUser gebruiken om een of meer rollen te verwijderen van een gebruiker in de database waar de rollen aanwezig zijn. Het commando revokeRolesFromUser heeft de volgende syntaxis:

db.runCommand(
  {
    revokeRolesFromUser: "<user>",
    roles: [
      { role: "<role>", db: "<database>" } | "<role>",
    ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

In de hierboven genoemde syntaxis kun je zowel door de gebruiker gedefinieerde als ingebouwde rollen opgeven in het veld roles. Net als bij het commando grantRolesToUser kun je de rol die je wilt intrekken in een document opgeven of de naam ervan gebruiken.

Om het commando revokeRolesFromUser met succes uit te voeren, moet je de actie revokeRole op de opgegeven database hebben.

Hier is een voorbeeld om het punt duidelijk te maken. De productUser00 entiteit in de producten database had de volgende rollen:

"roles" : [
  {
    "role" : "assetsWriter",
    "db" : "assets"
  },
  {
    "role" : "readWrite",
    "db" : "stock"
  },
  {
    "role" : "read",
    "db" : "products"
  }
]

Het volgende commando revokeRolesFromUser verwijdert twee rollen van de gebruiker: de rol “read” van products en de rol assetsWriter van de database “activa”:

use products
db.runCommand( { revokeRolesFromUser: "productUser00",
  roles: [
    { role: "AssetsWriter", db: "assets" },
    "read"
  ],
  writeConcern: { w: "majority" }
} )

De gebruiker “productUser00” in de products database heeft nu nog maar één rol over:

"roles" : [
  {
    "role" : "readWrite",
    "db" : "stock"
  }
]

Commando’s voor rolbeheer

Rollen verlenen gebruikers toegang tot resources. Verschillende ingebouwde rollen kunnen door beheerders worden gebruikt om de toegang tot een MongoDB systeem te regelen. Als de rollen niet de gewenste privileges dekken, kun je zelfs verder gaan om nieuwe rollen aan te maken in een bepaalde database.

dropRole

Met het commando dropRole kun je een door de gebruiker gedefinieerde rol verwijderen uit de database waarop je het commando uitvoert. Om dit commando uit te voeren gebruik je de volgende syntaxis:

db.runCommand(
  {
    dropRole: "<role>",
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

Voor een succesvolle uitvoering moet je de actie dropRole hebben op de opgegeven database. De volgende bewerkingen zouden de rol writeTags verwijderen uit de database “products”:

use products
db.runCommand(
  {
    dropRole: "writeTags",
    writeConcern: { w: "majority" }
  }
)
createRole

Je kunt het commando createRole gebruiken om een rol aan te maken en zijn privileges te specificeren. De rol geldt voor de database waarop je het commando uitvoert. Het commando createRole geeft een foutmelding als de rol al bestaat in de database.

Volg de gegeven syntaxis om dit commando uit te voeren:

db.adminCommand(
  {
    createRole: "<new role>",
    privileges: [
      { resource: { <resource> }, actions: [ "<action>", ... ] },
    ],
    roles: [
      { role: "<role>", db: "<database>" } | "<role>",
    ],
    authenticationRestrictions: [
      {
        clientSource: ["<IP>" | "<CIDR range>", ...],
        serverAddress: ["<IP>" | "<CIDR range>", ...]
      },
    ],
    writeConcern: <write concern document>,
    comment: <any> 
  }
)

De privileges van een rol gelden voor de database waarin de rol is aangemaakt. De rol kan privileges erven van andere rollen in zijn database. Bijvoorbeeld, een rol gemaakt binnen de “admin” database kan privileges bevatten die gelden voor een cluster of voor alle databases. Hij kan ook privileges erven van rollen in andere databases.

Om een rol in een database aan te maken heb je twee dingen nodig:

  1. De actie grantRole op die database om privileges te vermelden voor de nieuwe rol en ook om rollen te vermelden om van te erven.
  2. De createRole actie op die databaseresource.

Het volgende createRole commando maakt een clusterAdmin rol aan op de gebruikersdatabase:

db.adminCommand({ createRole: "clusterAdmin",
  privileges: [
    { resource: { cluster: true }, actions: [ "addShard" ] },
    { resource: { db: "config", collection: "" }, actions: [ "find", "remove" ] },
    { resource: { db: "users", collection: "usersCollection" }, actions: [ "update", "insert" ] },
    { resource: { db: "", collection: "" }, actions: [ "find" ] }
  ],
  roles: [
    { role: "read", db: "user" }
  ],
  writeConcern: { w: "majority" , wtimeout: 5000 }
})
grantRolesToRole

Met het commando grantRolesToRole kun je rollen toekennen aan een door de gebruiker gedefinieerde rol. Het grantRolesToRole commando zou van invloed zijn op rollen op de database waar het commando wordt uitgevoerd.

Dit grantRolesToRole commando heeft de volgende syntaxis:

db.runCommand(
  {
    grantRolesToRole: "<role>",
    roles: [
     { role: "<role>", db: "<database>" },
    ],
    writeConcern: { <write concern> },
    comment: <any> 
  }
)

De toegangsrechten zijn vergelijkbaar met het commando grantRolesToUser — je hebt een grantRole actie in een database nodig voor de juiste uitvoering van het commando.

In het volgende voorbeeld kun je het commando grantRolesToRole gebruiken om de rol productsReader in de database “products” bij te werken zodat hij de privileges van de rol productsWriter erft:

use products
db.runCommand(
  { 
    grantRolesToRole: "productsReader",
    roles: [
      "productsWriter"
    ],
    writeConcern: { w: "majority" , wtimeout: 5000 }
  }
)
revokePrivilegesFromRole

Je kunt revokePrivilegesFromRole gebruiken om de opgegeven privileges te verwijderen van de door de gebruiker gedefinieerde rol in de database waar het commando wordt uitgevoerd. Voor een goede uitvoering moet je de volgende syntaxis in gedachten houden:

db.runCommand(
  {
    revokePrivilegesFromRole: "<role>",
    privileges: [
      { resource: { <resource> }, actions: [ "<action>", ... ] },
    ],
    writeConcern: <write concern document>,
    comment: <any> 
  }
)

Om een privilege in te trekken moet het “resource document” patroon overeenkomen met het “resource” veld van dat privilege. Het “actions” veld kan een exacte overeenkomst of een subset zijn.

Neem bijvoorbeeld de rol manageRole in de products database met de volgende privileges die de “managers” database als resource specificeren:

{
  "resource" : {
    "db" : "managers",
    "collection" : ""
  },
  "actions" : [
    "insert",
    "remove"
  ]
}

Je kunt de “insert” of “remove” acties van slechts één collectie in de managers database niet intrekken. De volgende bewerkingen veroorzaken geen verandering in de rol:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges: [
      {
        resource : {
          db : "managers",
          collection : "kiosks"
        },
        actions : [
          "insert",
          "remove"
        ]
      }
    ]
  }
)
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges:
      [
        {
          resource : {
          db : "managers",
          collection : "kiosks"
        },
        actions : [
          "insert"
        ]
      }
    ]
  }
)

Om de “insert” en/of de “remove” acties van de rol manageRole in te trekken, moet deze precies overeenkomen met het resourcedocument. De volgende bewerking trekt bijvoorbeeld alleen de “remove” actie van het bestaande privilege in:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "manageRole",
    privileges:
      [
        {
          resource : {
            db : "managers",
            collection : ""
        },
        actions : [ "remove" ]
      }
    ]
  }
)

De volgende bewerking verwijdert meerdere privileges van de rol “executive” in de managers database:

use managers
db.runCommand(
  {
    revokePrivilegesFromRole: "executive",
    privileges: [
      {
        resource: { db: "managers", collection: "" },
        actions: [ "insert", "remove", "find" ]
      },
      {
        resource: { db: "managers", collection: "partners" },
        actions: [ "update" ]
      }
    ],
    writeConcern: { w: "majority" }
    }
)
rolesInfo

Het commando rolesInfo geeft informatie over privileges en overerving voor gespecificeerde rollen, inclusief ingebouwde en door de gebruiker gedefinieerde rollen. Je kunt ook het commando rolesInfo gebruiken om alle rollen op te vragen die in een database zijn ondergebracht.

Volg deze syntaxis voor een juiste uitvoering:

db.runCommand(
  {
    rolesInfo: { role: <name>, db: <db> },
    showPrivileges: <Boolean>,
    showBuiltinRoles: <Boolean>,
    comment: <any> 
  }
)

Om informatie voor een rol uit de huidige database terug te geven, kun je de naam ervan als volgt opgeven:

{ rolesInfo: "<rolename>" }

Om informatie voor een rol uit een andere database terug te geven, kun je de rol noemen met een document waarin de rol en de database worden genoemd:

{ rolesInfo: { role: "<rolename>", db: "<database>" } }

Het volgende commando geeft bijvoorbeeld de informatie over de rolovererving voor de rol executive gedefinieerd in de managers database:

db.runCommand(
   {
      rolesInfo: { role: "executive", db: "managers" }
   }
)

Dit volgende commando geeft de informatie over de rolovererving terug: accountManager op de database waarop het commando wordt uitgevoerd:

db.runCommand(
   {
      rolesInfo: "accountManager"
   }
)

Het volgende commando geeft zowel de privileges als de rolovererving voor de rol “executive” zoals gedefinieerd op de managers database:

db.runCommand(
   {
     rolesInfo: { role: "executive", db: "managers" },
     showPrivileges: true
   }
)

Om meerdere rollen te vermelden kun je een array gebruiken. Je kunt ook elke rol in de array vermelden als een string of document.

Een string moet je alleen gebruiken als de rol bestaat in de database waarop het commando wordt uitgevoerd:

{
  rolesInfo: [
    "<rolename>",
    { role: "<rolename>", db: "<database>" },
  ]
}

Het volgende commando geeft bijvoorbeeld informatie voor drie rollen voor drie verschillende databases:

db.runCommand(
   {
    rolesInfo: [
      { role: "executive", db: "managers" },
      { role: "accounts", db: "departments" },
      { role: "administrator", db: "products" }
    ]
  }
)

Je kunt zowel de privileges als de rolovererving als volgt krijgen:

db.runCommand(
  {
    rolesInfo: [
      { role: "executive", db: "managers" },
      { role: "accounts", db: "departments" },
      { role: "administrator", db: "products" }
    ],
    showPrivileges: true
  }
)

MongoDB documenten embedden voor betere prestaties

Met documentendatabases zoals MongoDB kun je je schema definiëren volgens je behoeften. Om optimale schema’s in MongoDB te maken, kun je de documenten nesten. Dus, in plaats van je applicatie af te stemmen op een datamodel, kun je een datamodel bouwen dat past bij je use case.

Met geneste documenten kun je gerelateerde gegevens opslaan die je samen opent. Bij het ontwerpen van schema’s voor MongoDB wordt aanbevolen om documenten standaard te embedden. Gebruik database-side of applicatie-side joins en referenties alleen als ze de moeite waard zijn.

Zorg ervoor dat de werklast zo vaak als nodig een document kan ophalen. Tegelijkertijd moet het document ook alle gegevens hebben die het nodig heeft. Dit is cruciaal voor uitzonderlijke prestaties van je applicatie.

Hieronder vind je een paar verschillende patronen om documenten in te sluiten:

Embedden documentpatroon

Hiermee kun je zelfs ingewikkelde substructuren inbedden in de documenten waarmee ze gebruikt worden. Door samenhangende gegevens in een enkel document te embedden, kun je het aantal read operaties dat nodig is om gegevens te krijgen, verminderen. In het algemeen moet je je schema zo structureren dat je applicatie alle benodigde informatie ontvangt in een enkele read operatie. Daarom is de regel om in gedachten te houden: wat samen wordt gebruikt, moet samen worden opgeslagen.

Embedden subsetpatroon

Het embedded subsetpatroon is een hybride geval. Je gebruikt het voor een aparte collectie van een lange lijst van gerelateerde items, waarbij je enkele van die items bij de hand kunt houden voor weergave.

Hier is een voorbeeld van een lijst met filmrecensies:

> db.movie.findOne()
{   
  _id: 321475,   
  title: "The Dark Knight"
}  
> db.review.find({movie_id: 321475})
{   
  _id: 264579,   
  movie_id: 321475,   
  stars: 4   
  text: "Amazing"   
}
{   
  _id: 375684,   
  movie_id: 321475,   
  stars:5,   
  text: "Mindblowing"
}

Stel je nu duizend soortgelijke recensies voor, maar je bent van plan alleen de meest recente twee weer te geven als je een film laat zien. In dit scenario is het zinvol om die subset op te slaan als een lijst in het filmdocument:

> db.movie.findOne({_id: 321475})   
{   
  _id: 321475,   
  title: "The Dark Knight",   
  recent_reviews: [   
    {_id: 264579, stars: 4, text: "Amazing"},   
    {_id: 375684, stars: 5, text: "Mindblowing"}   
  ]   
}</code

Simpel gezegd: als je routinematig een subset van verwante items raadpleegt, zorg er dan voor dat je die embedt.

Onafhankelijke toegang

Misschien wil je subdocumenten opslaan in hun collectie om ze te scheiden van hun bovenliggende collectie.

Neem bijvoorbeeld de productlijn van een bedrijf. Als het bedrijf een kleine reeks producten verkoopt, wil je ze misschien opslaan in het bedrijfsdocument. Maar als je ze in verschillende bedrijven wilt hergebruiken of ze direct op hun stock keeping unit (SKU) wilt openen, dan zou je ze ook in hun collectie willen opslaan.

Als je een entiteit zelfstandig manipuleert of benadert, maak dan een collectie om die apart op te slaan voor de best practice.

Niet-gebonden lijsten

Het opslaan van korte lijsten met gerelateerde informatie in hun document heeft een nadeel. Als je lijst onbegrensd blijft groeien, moet je hem niet in één document zetten. Dit komt omdat je het niet lang zou kunnen ondersteunen.

Hier zijn twee redenen voor. Ten eerste heeft MongoDB een limiet op de grootte van een enkel document. Ten tweede, als je het document te frequent opvraagt, zul je negatieve resultaten zien door ongecontroleerd geheugengebruik.

Simpel gezegd: als een lijst onbegrensd begint te groeien, maak dan een collectie om hem apart op te slaan.

Uitgebreid referentiepatroon

Het uitgebreide referentiepatroon lijkt op het subsetpatroon. Het optimaliseert ook informatie die je regelmatig gebruikt om op het document op te slaan.

Hier wordt, in plaats van een lijst, gebruik gemaakt wanneer een document verwijst naar een ander dat in dezelfde collectie aanwezig is. Tegelijkertijd slaat het ook enkele velden van dat andere document op voor gemakkelijke toegang.

Bijvoorbeeld:

> db.movie.findOne({_id: 245434})
{   
  _id: 245434,   
  title: "Mission Impossible 4 - Ghost Protocol",   
  studio_id: 924935,   
  studio_name: "Paramount Pictures"   
}

Zoals je ziet wordt “de studio_id” opgeslagen, zodat je meer informatie kunt opzoeken over de studio die de film gemaakt heeft. Maar de naam van de studio is voor de eenvoud ook naar dit document gekopieerd.

Om regelmatig informatie uit gewijzigde documenten te embeddden, moet je eraan denken om de documenten waarin je die informatie hebt gekopieerd bij te werken als ze worden gewijzigd. Met andere woorden, als je routinematig bepaalde velden uit een document waarnaar wordt verwezen callt, sluit ze dan in.

MongoDB monitoren

Je kunt monitoringtools zoals Kinsta APM gebruiken om lange API calls, trage database queries, lange externe URL requests te debuggen, om er een paar te noemen. Je kunt zelfs commando’s inzetten om de databaseprestaties te verbeteren. Je kunt ze ook gebruiken om de gezondheid van je database instances te inspecteren.

Waarom zou je MongoDB Databases moeten monitoren?

Een belangrijk aspect van databasebeheerplanning is het monitoren van de prestaties en gezondheid van je cluster. MongoDB Atlas neemt het meeste beheer voor zijn rekening door zijn fouttolerantie/schaalbaarheid.

Desondanks moeten gebruikers weten hoe ze clusters kunnen tracken. Ze moeten ook weten hoe ze kunnen schalen of tweaken wat ze nodig hebben voordat ze in een crisis raken.

Door MongoDB databases te monitoren kun je:

  • Het gebruik van resources observeren.
  • De huidige capaciteit van je database begrijpen.
  • Reageren en real-time problemen opsporen om je applicatiestack te verbeteren.
  • De aanwezigheid van prestatieproblemen en abnormaal gedrag observeren.
  • Afstemmen op eisen wat betreftgovernance/gegevensbescherming en service-level agreement (SLA).

Belangrijke meetgegevens om te monitoren

Tijdens het monitoren van MongoDB zijn er vier belangrijke aspecten die je in gedachten moet houden:

MongoDB hardwarestatistieken

Hier zijn de primaire statistieken voor het monitoren van de hardware:

Normalized Process CPU

Dit wordt gedefinieerd als het percentage van de tijd dat de CPU besteedt aan applicatiesoftware die het MongoDB proces onderhoudt.

Je kunt dit schalen naar een bereik van 0-100% door het te delen door het aantal CPU cores. Het bevat CPU dat wordt gebruikt door modules als kernel en user.

Een hoge kernel CPU kan wijzen op uitputting van de CPU via de operaties van het besturingssysteem. De gebruiker gekoppeld aan MongoDB operaties kan de hoofdoorzaak zijn van CPU uitputting.

Normalized System CPU

Dit is het percentage van de tijd dat de CPU besteedt aan systeemoproepen voor dit MongoDB proces. Je kunt het schalen naar een bereik van 0-100% door het te delen door het aantal CPU-kernen. Het bevat ook de CPU die gebruikt wordt door modules als iowait, user, kernel, steal, enz.

User CPU of hoge kernel zou kunnen wijzen op CPU uitputting door MongoDB bewerkingen (software). Hoge iowait kan verband houden met uitputting van de opslag die CPU uitputting veroorzaakt.

Disk IOPS

Schijf IOPS is de gemiddelde verbruikte IO operaties per seconde op de schijfpartitie van MongoDB.

Disk Latency

Dit is de lees- en schrijfvertraging van de schijfpartitie in MongoDB in milliseconden. Hoge waarden (>500ms) geven aan dat de opslaglaag de prestaties van MongoDB kan beïnvloeden.

System Memory

Gebruik het systeemgeheugen om de gebruikte fysieke geheugenbytes tegenover de beschikbare vrije ruimte te beschrijven.

De beschikbare metriek benadert het aantal beschikbare bytes systeemgeheugen. Je kunt dit gebruiken om nieuwe applicaties uit te voeren, zonder te swappen.

Disk Space Free

Dit is gedefinieerd als de totale bytes vrije schijfruimte op de schijfpartitie van MongoDB. MongoDB Atlas biedt auto-scaling mogelijkheden op basis van deze metriek.

Swap Usage

Je kunt een swapgebruikgrafiek gebruiken om te beschrijven hoeveel geheugen er op het swapapparaat wordt gezet. Een hoog gebruikte metriek in deze grafiek laat zien dat swap wordt gebruikt. Dit geeft aan dat er te weinig geheugen beschikbaar is voor de huidige werklast.

MongoDB Cluster Connection en Operation statistieken

Hier zijn de belangrijkste statistieken voor Operation en Connection statistieken:

Operation Execution Times

De gemiddelde bewerkingstijd (schrijf- en leesbewerkingen) uitgevoerd over de geselecteerde steekproefperiode.

Opcounters

Het gemiddelde aantal uitgevoerde operaties per seconde over de geselecteerde steekproefperiode. Opcounters grafiek/metriek toont de uitsplitsing van operatietypes en snelheid voor de instantie.

Connections

Deze metriek verwijst naar het aantal open verbindingen met de instantie. Hoge pieken of aantallen kunnen wijzen op een suboptimale verbindingsstrategie, hetzij van de niet reagerende server, hetzij van de kant van de client.

Query Targeting and Query Executors

Dit is de gemiddelde snelheid per seconde over de geselecteerde periode van gescande documenten. Voor query uitvoerders is dit tijdens de evaluatie van queryplannen en queries. Query targeting toont de verhouding tussen het aantal gescande documenten en het aantal geretourneerde documenten.

Een hoge ratio wijst op suboptimale operaties. Deze bewerkingen scannen veel documenten om een kleiner deel terug te geven.

Scan and Order

Het beschrijft de gemiddelde snelheid per seconde over de gekozen steekproefperiode van zoekopdrachten. Het geeft gesorteerde resultaten terug die de sorteeroperatie niet kunnen uitvoeren met behulp van een index.

Queues

Queues kunnen het aantal operaties beschrijven die wachten op een slot, hetzij schrijven, hetzij lezen. Hoge wachtrijen kunnen wijzen op een minder dan optimaal schemaontwerp. Het kan ook wijzen op conflicterende schrijfpaden, waardoor de concurrentie om databaseresources groot is.

MongoDB replicatiestatistieken

Dit zijn de primaire statistieken voor replicatiemonitoring:

Replication Oplog Window

Deze metriek vermeldt bij benadering het aantal beschikbare uren in de primaire replicatie oplog . Als een secundaire meer dan dit aantal uren achterloopt, kan hij het niet bijhouden en heeft hij een volledige hersynchronisatie nodig.

Replication Lag

Replication lag is gedefinieerd als het geschatte aantal seconden dat een secundaire node achterloopt op de primaire node bij schrijfoperaties. Een hoge replication lag wijst op een secundaire die moeite heeft met repliceren. Het kan de latency van je operatie beïnvloeden, gezien de lees/schrijf concern van de verbindingen.

Replication Headroom

Deze metriek verwijst naar het verschil tussen het oplog venster van de primaire replicatie en de replicatievertraging van de secundaire. Als deze waarde naar nul gaat, kan dat ertoe leiden dat een secundaire in de modus RECOVERING gaat.

Opcounters – repl

Opcounters – repl is gedefinieerd als het gemiddelde aantal uitgevoerde replicatiebewerkingen per seconde voor de gekozen steekproefperiode. Met de opcounters -graph/metric kun je kijken naar de operatiesnelheid en de verdeling van de operatietypes voor de gespecificeerde instantie.

Oplog GB/Hour

Dit is gedefinieerd als het gemiddelde aantal gigabytes oplog dat de primary per uur genereert. Hoge onverwachte volumes oplog kunnen wijzen op een zeer onvoldoende schrijfwerklast of een probleem met het schema-ontwerp.

MongoDB tools voor prestatiemonitoring

MongoDB heeft in Cloud Manager, Atlas en Ops Manager ingebouwde gebruikersinterface tools voor het bijhouden van de prestaties. Het biedt ook enkele onafhankelijke commando’s en tools om naar meer ruwe gegevens te kijken. We zullen het hebben over enkele tools die je kunt uitvoeren vanaf een host die toegang en de juiste rollen heeft om je omgeving te checken:

mongotop

Je kunt dit commando gebruiken om bij te houden hoeveel tijd een MongoDB instance besteedt aan het schrijven en lezen van gegevens per collectie. Gebruik de volgende syntaxis:

mongotop <options> <connection-string> <polling-interval in seconden>

rs.status()

Dit commando geeft de status van de replicaset terug. Het wordt uitgevoerd vanuit het oogpunt van het lid waar de methode wordt uitgevoerd.

mongostat

Je kunt het commando mongostat gebruiken om een snel overzicht te krijgen van de status van je MongoDB serverinstantie. Voor een optimale uitvoer kun je het gebruiken om een enkele instantie te bekijken voor een specifieke gebeurtenis, omdat het een real-time weergave biedt.

Gebruik dit commando om elementaire serverstatistieken te controleren, zoals lock-wachtrijen, uitsplitsing van operaties, MongoDB geheugenstatistieken en verbindingen/netwerk:

mongostat <options> <connection-string> <polling-interval in seconden>

dbStats

Dit commando geeft opslagstatistieken voor een specifieke database, zoals het aantal indexen en hun grootte, totale collectiegegevens versus opslaggrootte, en collectie gerelateerde statistieken (aantal collecties en documenten).

db.serverStatus()

Je kunt het commando db.serverStatus() gebruiken om een overzicht te krijgen van de toestand van de database. Het geeft je een document dat de metriccounters van de huidige instance weergeeft. Voer dit commando regelmatig uit om statistieken over de instantie te verzamelen.

collStats

Het commando collStats verzamelt soortgelijke statistieken als dbStats op het niveau van de collectie. De uitvoer bestaat uit een telling van objecten in de collectie, de hoeveelheid schijfruimte die de collectie gebruikt, de grootte van de collectie en informatie over de indexen voor een bepaalde collectie.

Je kunt al deze commando’s gebruiken om real-time rapportage en bewaking van de databaseserver te bieden, waarmee je de databaseprestaties en -fouten in de gaten kunt houden en waarmee je geïnformeerde beslissingen kunt nemen om een database te verfijnen.

Een MongoDB database verwijderen

Om een database die je in MongoDB hebt aangemaakt te droppen, moet je er verbinding mee maken via het use keyword.

Stel dat je een database hebt gemaakt met de naam “Engineers”. Om verbinding te maken met de database gebruik je het volgende commando:

use Engineers

Typ vervolgens db.dropDatabase() om van deze database af te komen. Na uitvoering is dit het resultaat dat je kunt verwachten:

{ "dropped"  :  "Engineers", "ok" : 1 }

Je kunt het commando showdbs uitvoeren om te controleren of de database nog bestaat.

Samenvatting

Om elke laatste druppel aan waarde uit MongoDB te persen, moet je een sterk begrip hebben van de grondbeginselen. Vandaar dat het van cruciaal belang is om MongoDB databases door en door te kennen. Daarvoor moet je je eerst vertrouwd maken met de methoden om een database te maken.

In dit artikel belichten we de verschillende methoden die je kunt gebruiken om een database in MongoDB te maken, gevolgd door een gedetailleerde beschrijving van enkele handige MongoDB commando’s om je databases te beheren. Tenslotte ronden we de discussie af door te bespreken hoe je gebruik kunt maken van embedded documenten en tools voor prestatiebewaking in MongoDB om ervoor te zorgen dat je workflow optimaal functioneert.

Wat is jouw mening over deze MongoDB commando’s? Hebben we een aspect of methode gemist die je hier graag had gezien? Laat het ons weten in de commentaren!

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.