En fonction de vos exigences pour votre logiciel, vous pouvez donner la priorité à la flexibilité, à l’évolutivité, aux performances ou à la vitesse. Par conséquent, les développeurs et les entreprises sont souvent désorientés lorsqu’ils choisissent une base de données pour leurs besoins. Si vous avez besoin d’une base de données qui offre une flexibilité et une évolutivité élevées, ainsi que l’agrégation de données pour l’analyse des clients, MongoDB est peut-être la solution qu’il vous faut !

Dans cet article, nous allons aborder la structure de la base de données MongoDB et comment créer, surveiller et gérer votre base de données ! Commençons.

Comment est structurée une base de données MongoDB ?

MongoDB est une base de données NoSQL sans schéma. Cela signifie que vous ne spécifiez pas de structure pour les tables/bases de données comme vous le faites pour les bases de données SQL.

Saviez-vous que les bases de données NoSQL sont en fait plus rapides que les bases de données relationnelles ? Cela est dû à des caractéristiques comme l’indexation, le sharding et les pipelines d’agrégation. MongoDB est également connu pour sa rapidité d’exécution des requêtes. C’est pourquoi il est préféré par des entreprises comme Google, Toyota et Forbes.

Ci-dessous, nous allons explorer quelques caractéristiques clés de MongoDB.

Documents

MongoDB possède un modèle de données de type document qui stocke les données sous forme de documents JSON. Les documents correspondent naturellement aux objets du code de l’application, ce qui rend son utilisation plus simple pour les développeurs.

Dans une table de base de données relationnelle, vous devez ajouter une colonne pour ajouter un nouveau champ. Ce n’est pas le cas avec les champs dans un document JSON. Les champs d’un document JSON peuvent différer d’un document à l’autre, ils ne seront donc pas ajoutés à chaque enregistrement de la base de données.

Les documents peuvent stocker des structures comme des tableaux qui peuvent être imbriqués pour exprimer des relations hiérarchiques. En outre, MongoDB convertit les documents en un type JSON binaire (BSON). Cela garantit un accès plus rapide et une prise en charge accrue de divers types de données comme les chaînes de caractères, les nombres entiers, les nombres booléens, et bien plus encore !

Jeux de répliques

Lorsque vous créez une nouvelle base de données dans MongoDB, le système crée automatiquement au moins 2 copies supplémentaires de vos données. Ces copies sont connues sous le nom de « replica sets », et elles répliquent continuellement les données entre elles, assurant ainsi une meilleure disponibilité de vos données. Elles offrent également une protection contre les temps d’arrêt lors d’une panne du système ou d’une maintenance planifiée.

Collections

Une collection est un groupe de documents associés à une base de données. Elles sont similaires aux tables des bases de données relationnelles.

Les collections sont toutefois beaucoup plus flexibles. D’une part, elles ne dépendent pas d’un schéma. Deuxièmement, les documents ne doivent pas nécessairement être du même type de données !

Pour afficher une liste des collections qui appartiennent à une base de données, utilisez la commande listCollections.

Pipelines d’agrégation

Vous pouvez utiliser ce framework pour agréger plusieurs opérateurs et expressions. Il est flexible car il vous permet de traiter, de transformer et d’analyser des données de toute structure.

Pour cette raison, MongoDB permet des flux de données rapides et des fonctionnalités à travers 150 opérateurs et expressions. Il dispose également de plusieurs étapes, comme l’étape d’union, qui rassemble de manière flexible les résultats de plusieurs collections.

Index

Vous pouvez indexer n’importe quel champ d’un document MongoDB pour augmenter son efficacité et améliorer la vitesse des requêtes. L’indexation permet de gagner du temps en parcourant l’index pour limiter les documents inspectés. N’est-ce pas bien mieux que de lire chaque document de la collection ?

Vous pouvez utiliser diverses stratégies d’indexation, notamment des index composés sur plusieurs champs. Par exemple, disons que vous avez plusieurs documents contenant le prénom et le nom de l’employé dans des champs séparés. Si vous souhaitez que le prénom et le nom soient retournés, vous pouvez créer un index qui inclut à la fois « Nom » et « Prénom ». Ce serait bien mieux que d’avoir un index sur « Nom » et un autre sur « Prénom ».

Vous pouvez utiliser des outils comme Performance Advisor pour mieux comprendre quelle requête pourrait bénéficier des index.

Sharding

Le sharding répartit un ensemble de données unique entre plusieurs bases de données. Cet ensemble de données peut ensuite être stocké sur plusieurs machines pour augmenter la capacité de stockage totale d’un système. En effet, il divise les grands ensembles de données en petits morceaux et les stocke dans différents nœuds de données.

MongoDB partage les données au niveau de la collection, en distribuant les documents d’une collection à travers les shards d’un cluster. Cela garantit l’évolutivité en permettant à l’architecture de gérer les plus grandes applications.

Comment créer une base de données MongoDB

Vous devez d’abord installer le bon paquetage MongoDB adapté à votre système d’exploitation. Rendez-vous sur la page Télécharger MongoDB Community Server. Parmi les options disponibles, sélectionnez la dernière « version », le format du « paquet » comme fichier zip et la « plateforme » comme votre système d’exploitation, puis cliquez sur « Télécharger » comme illustré ci-dessous :

Processus de téléchargement de MongoDB Community Server
Processus de téléchargement de MongoDB Community Server. (Source de l’image : serveur communautaire MongoDB)

Le processus est assez simple, vous aurez donc MongoDB installé dans votre système en un rien de temps !

Une fois l’installation terminée, ouvrez votre invite de commande et saisissez mongod -version pour la vérifier. Si vous n’obtenez pas le résultat suivant et que vous voyez plutôt une série d’erreurs, vous devrez peut-être réinstaller le système :

Vérification de la version de MongoDB
Vérification de la version de MongoDB. (Image source : configserverfirewall)

Utilisation du shell MongoDB

Avant de commencer, assurez-vous que :

  • Votre client dispose de Transport Layer Security et se trouve sur votre liste d’IP autorisées.
  • Vous disposez d’un compte utilisateur et d’un mot de passe sur le cluster MongoDB souhaité.
  • Vous avez installé MongoDB sur votre appareil.

Étape 1 : Accédez au shell MongoDB

Démarrez le serveur MongoDB en suivant les instructions de chaque système d’exploitation. Pour Windows, saisissez la commande suivante. Pour les autres systèmes d’exploitation, reportez-vous à la documentation de MongoDB.

net start MongoDB

Ceci devrait donner la sortie suivante :

Utiliser le serveur MongoDB
Utiliser le serveur MongoDB (Source de l’image : c-sharpcorner)

La commande précédente a initialisé le serveur MongoDB. Pour l’exécuter, nous devrions saisir mongo dans l’invite de commande.

Utilisez l'interpréteur de commandes MongoDB
Utilisez l’interpréteur de commandes MongoDB (Image source : bmc)

Ici, dans le shell MongoDB, nous pouvons exécuter des commandes pour créer des bases de données, insérer des données, modifier des données, émettre des commandes administratives et supprimer des données.

Étape 2 : Créez votre base de données

Contrairement aux bases de données relationnelles courantes, MongoDB n’a pas de commande de création de base de données. Au lieu de cela, il existe un mot-clé appelé use qui permet de basculer vers une base de données spécifiée. Si la base de données n’existe pas, il créera une nouvelle base de données, sinon, il établira un lien avec la base de données existante.

Par exemple, pour lancer une base de données appelée « Company », saisissez :

use Company
Création d'une base de données dans MongoDB.
Création d’une base de données dans MongoDB.

Vous pouvez saisir db pour confirmer la base de données que vous venez de créer dans votre système. Si la nouvelle base de données que vous avez créée s’affiche, vous vous êtes bien connecté à celle-ci.

Si vous voulez vérifier les bases de données existantes, saisissez show dbs et cela vous donnera toutes les bases de données de votre système :

Affichage des bases de données dans MongoDB.
Affichage des bases de données dans MongoDB.

Par défaut, l’installation de MongoDB crée les bases de données admin, config et locale.

Avez-vous remarqué que la base de données que nous avons créée n’est pas affichée ? C’est parce que nous n’avons pas encore enregistré de valeurs dans la base de données ! Nous aborderons l’insertion dans la section sur la gestion des bases de données.

Utilisation de l’interface utilisateur Atlas

Vous pouvez également commencer par utiliser le service de base de données de MongoDB, Atlas. Bien que vous deviez payer pour accéder à certaines fonctionnalités d’Atlas, la plupart des fonctionnalités de la base de données sont disponibles avec le volet gratuit. Les fonctionnalités du volet gratuit sont plus que suffisantes pour créer une base de données MongoDB.

Avant de commencer, assurez-vous que :

  1. Votre IP est sur la liste d’autorisation.
  2. Vous avez un compte d’utilisateur et un mot de passe sur le cluster MongoDB que vous souhaitez utiliser.

Pour créer une base de données MongoDB avec AtlasUI, ouvrez une fenêtre de navigateur et connectez-vous à https://cloud.mongodb.com. À partir de la page de votre cluster, cliquez sur Parcourir les collections. S’il n’y a pas de bases de données dans le cluster, vous pouvez créer votre base de données en cliquant sur le bouton Ajouter mes propres données.

L’invite vous demandera de fournir un nom de base de données et de collection. Une fois que vous les avez nommés, cliquez sur Créer, et le tour est joué ! Vous pouvez maintenant saisir de nouveaux documents ou vous connecter à la base de données à l’aide de pilotes.

Gestion de votre base de données MongoDB

Dans cette section, nous allons passer en revue quelques moyens astucieux de gérer efficacement votre base de données MongoDB. Vous pouvez le faire soit en utilisant la boussole MongoDB, soit par le biais de collections.

Utilisation des collections

Alors que les bases de données relationnelles possèdent des tables bien définies avec des types de données et des colonnes spécifiques, NoSQL dispose de collections au lieu de tables. Ces collections n’ont aucune structure, et les documents peuvent varier – vous pouvez avoir différents types de données et champs sans devoir correspondre au format d’un autre document dans la même collection.

Pour faire une démonstration, créons une collection appelée « Employee » et ajoutons-y un document :

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

Si l’insertion est réussie, elle renverra WriteResult({ "nInserted" : 1 }):

Insertion réussie dans MongoDB.
Insertion réussie dans MongoDB.

Ici, « db » fait référence à la base de données actuellement connectée. « Employee » est la collection nouvellement créée sur la base de données de l’entreprise.

Nous n’avons pas défini de clé primaire ici car MongoDB crée automatiquement un champ de clé primaire appelé « _id » et lui attribue une valeur par défaut.

Exécutez la commande ci-dessous pour consulter la collection au format JSON :

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

Sortie :

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

Bien que la valeur « _id » soit attribuée automatiquement, vous pouvez modifier la valeur de la clé primaire par défaut. Cette fois, nous allons insérer un autre document dans la base de données « Employee », avec la valeur « _id » comme « 1 » :

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

En exécutant la commande db.Employee.find().forEach(printjson), nous obtenons le résultat suivant :

Documents dans la collection avec leur clé primaire.
Documents dans la collection avec leur clé primaire.

Dans le résultat ci-dessus, la valeur « _id » pour « Ava » est définie sur « 1 » au lieu de se voir attribuer une valeur automatiquement.

Maintenant que nous avons réussi à ajouter des valeurs dans la base de données, nous pouvons vérifier si elle apparaît sous les bases de données existantes dans notre système en utilisant la commande suivante :

show dbs
Affichage de la liste des bases de données.
Affichage de la liste des bases de données.

Et voilà ! Vous avez réussi à créer une base de données dans votre système !

Utilisation de MongoDB Compass

Bien que nous puissions travailler avec les serveurs MongoDB à partir du shell Mongo, cela peut parfois être fastidieux. Vous pourriez en faire l’expérience dans un environnement de production.

Cependant, il existe un outil de compas (nommé à juste titre Compass) créé par MongoDB qui peut vous faciliter la tâche. Il dispose d’une meilleure interface graphique et de fonctionnalités supplémentaires telles que la visualisation des données, le profilage des performances et l’accès CRUD (create, read, update, delete) aux données, aux bases de données et aux collections.

Vous pouvez télécharger l’IDE Compass pour votre système d’exploitation et l’installer grâce à son processus simple.

Ensuite, ouvrez l’application et créez une connexion avec le serveur en collant la chaîne de connexion. Si vous ne la trouvez pas, vous pouvez cliquer sur Remplir les champs de connexion individuellement. Si vous n’avez pas modifié le numéro de port lors de l’installation de MongoDB, cliquez simplement sur le bouton de connexion, et vous y êtes ! Sinon, entrez simplement les valeurs que vous avez définies et cliquez sur Connecter.

Fenêtre Nouvelle connexion dans MongoDB
Fenêtre Nouvelle connexion dans MongoDB. (Image source : mongodb)

Ensuite, fournissez le nom d’hôte, le port et l’authentification dans la fenêtre Nouvelle connexion.

Dans MongoDB Compass, vous pouvez créer une base de données et ajouter sa première collection simultanément. Voici comment procéder :

  1. Cliquez sur Créer une base de données pour ouvrir l’invite.
  2. Saisissez le nom de la base de données et sa première collection.
  3. Cliquez sur Créer une base de données.

Vous pouvez insérer d’autres documents dans votre base de données en cliquant sur le nom de votre base de données, puis en cliquant sur le nom de la collection pour voir l’onglet Documents. Vous pouvez ensuite cliquer sur le bouton Ajouter des données pour insérer un ou plusieurs documents dans votre collection.

Lorsque vous ajoutez vos documents, vous pouvez les saisir un par un ou sous forme de documents multiples dans un tableau. Si vous ajoutez plusieurs documents, assurez-vous que ces documents séparés par des virgules sont placés entre crochets. Par exemple :

{ _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" ] }

Enfin, cliquez sur Insérer pour ajouter les documents à votre collection. Voici à quoi ressemblerait le corps d’un document :

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

Ici, les noms des champs sont « StudentID » et « StudentName ». Les valeurs des champs sont respectivement « 1 » et « JohnDoe ».

Commandes utiles

Vous pouvez gérer ces collections grâce aux commandes de gestion des rôles et de gestion des utilisateurs.

Commandes de gestion des utilisateurs

Les commandes de gestion des utilisateurs MongoDB contiennent des commandes qui se rapportent à l’utilisateur. Nous pouvons créer, mettre à jour et supprimer les utilisateurs à l’aide de ces commandes.

dropUser

Cette commande supprime un seul utilisateur de la base de données spécifiée. Voici la syntaxe :

db.dropUser(username, writeConcern)

Ici, username est un champ pré-requis qui spécifie le nom de l’utilisateur à retirer de la base de données. Le champ facultatif writeConcern contient le niveau de préoccupation en écriture pour l’opération de retrait. Le niveau de préoccupation en écriture peut être déterminé par le champ facultatif writeConcern.

Avant de supprimer un utilisateur qui a le rôle userAdminAnyDatabase, assurez-vous qu’il y a au moins un autre utilisateur avec des privilèges d’administration d’utilisateur.

Dans cet exemple, nous allons abandonner l’utilisateur « user26 » dans la base de données de test :

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

Sortie :

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

Cette commande crée un nouvel utilisateur pour la base de données spécifiée comme suit :

db.createUser(user, writeConcern)

Ici, user est un champ obligatoire qui contient le document avec les informations d’authentification et d’accès sur l’utilisateur à créer. Le champ facultatif writeConcern contient le niveau de préoccupation en écriture pour l’opération de création. Le niveau de préoccupation en écriture peut être déterminé par le champ facultatif writeConcern.

createUser renverra une erreur de duplication d’utilisateur si l’utilisateur existe déjà dans la base de données.

Vous pouvez créer un nouvel utilisateur dans la base de données de test comme suit :

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

La sortie est la suivante :

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

Vous pouvez utiliser cette commande pour accorder des rôles supplémentaires à un utilisateur. Pour l’utiliser, vous devez garder à l’esprit la syntaxe suivante :

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

Vous pouvez spécifier à la fois des rôles définis par l’utilisateur et des rôles intégrés dans les rôles mentionnés ci-dessus. Si vous voulez spécifier un rôle qui existe dans la même base de données où s’exécute grantRolesToUser, vous pouvez soit spécifier le rôle avec un document, comme mentionné ci-dessous :

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

Ou, vous pouvez simplement spécifier le rôle avec le nom du rôle. Par exemple :

"readWrite"

Si vous voulez spécifier le rôle qui est présent dans une base de données différente, vous devrez spécifier le rôle avec un document différent.

Pour accorder un rôle sur une base de données, vous avez besoin de l’action grantRole sur la base de données spécifiée.

Voici un exemple pour vous donner une idée claire. Prenons l’exemple d’un utilisateur productUser00 dans la base de données des produits avec les rôles suivants :

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

L’opération grantRolesToUser fournit à « productUser00 » le rôle readWrite sur la base de données des stocks et le rôle de lecture sur la base de données des produits :

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

L’utilisateur productUser00 de la base de données des produits possède maintenant les rôles suivants :

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

Vous pouvez utiliser la commande usersInfo pour renvoyer des informations sur un ou plusieurs utilisateurs. Voici la syntaxe :

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

En termes d’accès, les utilisateurs peuvent toujours consulter leurs propres informations. Pour consulter les informations d’un autre utilisateur, l’utilisateur qui exécute la commande doit avoir des privilèges qui incluent l’action viewUser sur la base de données de l’autre utilisateur.

En exécutant la commande userInfo, vous pouvez obtenir les informations suivantes en fonction des options spécifiées :

{
  "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
} 

Maintenant que vous avez une idée générale de ce que vous pouvez accomplir avec la commande usersInfo, la prochaine question évidente qui pourrait surgir est la suivante : quelles commandes seraient utiles pour examiner des utilisateurs spécifiques et plusieurs utilisateurs ?

Voici deux exemples pratiques pour illustrer cette question :
Pour consulter les privilèges et informations spécifiques à des utilisateurs particuliers, mais pas les informations d’identification, pour un utilisateur « Anthony » défini dans la base de données « office », exécutez la commande suivante :

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

Si vous voulez regarder un utilisateur dans la base de données actuelle, vous ne pouvez mentionner l’utilisateur que par son nom. Par exemple, si vous êtes dans la base de données « home » et qu’un utilisateur nommé « « Timothy » existe dans la base de données « home », vous pouvez exécuter la commande suivante :

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

Ensuite, vous pouvez utiliser un tableau si vous souhaitez consulter les informations de plusieurs utilisateurs. Vous pouvez soit inclure les champs facultatifs showCredentials et showPrivileges, soit choisir de ne pas les inclure. Voici à quoi ressemblerait la commande :

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

Vous pouvez utiliser la commande revokeRolesFromUser pour supprimer un ou plusieurs rôles d’un utilisateur sur la base de données où les rôles sont présents. La commande revokeRolesFromUser a la syntaxe suivante :

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

Dans la syntaxe mentionnée ci-dessus, vous pouvez spécifier à la fois des rôles définis par l’utilisateur et des rôles intégrés dans le champ roles. Comme pour la commande grantRolesToUser, vous pouvez spécifier le rôle que vous souhaitez révoquer dans un document ou utiliser son nom.

Pour exécuter avec succès la commande revokeRolesFromUser, vous devez disposer de l’action revokeRole sur la base de données spécifiée.

Voici un exemple pour illustrer ce point. L’entité productUser00 de la base de données des produits avait les rôles suivants :

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

La commande suivante revokeRolesFromUser supprimera deux des rôles de l’utilisateur : le rôle « read » de products et le rôle assetsWriter de la base de données « assets » :

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

L’utilisateur « productUser00 » de la base de données des produits n’a maintenant plus qu’un seul rôle :

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

Commandes de gestion des rôles

Les rôles accordent aux utilisateurs l’accès aux ressources. Plusieurs rôles intégrés peuvent être utilisés par les administrateurs pour contrôler l’accès à un système MongoDB. Si les rôles ne couvrent pas les privilèges souhaités, vous pouvez même aller plus loin en créant de nouveaux rôles dans une base de données particulière.

dropRole

Avec la commande dropRole, vous pouvez supprimer un rôle défini par l’utilisateur de la base de données sur laquelle vous exécutez la commande. Pour exécuter cette commande, utilisez la syntaxe suivante :

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

Pour une exécution réussie, vous devez disposer de l’action dropRole sur la base de données spécifiée. Les opérations suivantes supprimeraient le rôle writeTags de la base de données « products » :

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

Vous pouvez utiliser la commande createRole pour créer un rôle et spécifier ses privilèges. Le rôle s’appliquera à la base de données sur laquelle vous choisissez d’exécuter la commande. La commande createRole renverrait une erreur de rôle dupliqué si le rôle existe déjà dans la base de données.

Pour exécuter cette commande, suivez la syntaxe donnée :

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> 
  }
)

Les privilèges d’un rôle s’appliquent à la base de données dans laquelle le rôle a été créé. Le rôle peut hériter des privilèges d’autres rôles dans sa base de données. Par exemple, un rôle créé sur la base de données « admin » peut inclure des privilèges qui s’appliquent soit à un cluster, soit à toutes les bases de données. Il peut également hériter de privilèges de rôles présents dans d’autres bases de données.

Pour créer un rôle dans une base de données, vous devez disposer de deux éléments :

  1. L’action grantRole sur cette base de données pour mentionner les privilèges du nouveau rôle ainsi que pour mentionner les rôles dont il doit hériter.
  2. L’action createRole sur cette ressource de base de données.

La commande suivante createRole créera un rôle clusterAdmin sur la base de données des utilisateurs :

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

Avec la commande grantRolesToRole, vous pouvez accorder des rôles à un rôle défini par l’utilisateur. La commande grantRolesToRole affecterait les rôles sur la base de données où la commande est exécutée.

Cette commande grantRolesToRole a la syntaxe suivante :

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

Les privilèges d’accès sont similaires à ceux de la commande grantRolesToUser — vous avez besoin d’une action grantRole sur une base de données pour la bonne exécution de la commande.

Dans l’exemple suivant, vous pouvez utiliser la commande grantRolesToRole pour mettre à jour le rôle productsReader dans la base de données « produits » afin d’hériter des privilèges du rôle productsWriter:

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

Vous pouvez utiliser revokePrivilegesFromRole pour supprimer les privilèges spécifiés du rôle défini par l’utilisateur sur la base de données où la commande est exécutée. Pour une exécution correcte, vous devez garder à l’esprit la syntaxe suivante :

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

Pour révoquer un privilège, « resource document » doit correspondre au champ « resource » de ce privilège. Le champ « actions » peut être soit une correspondance exacte, soit un sous-ensemble.

Par exemple, considérons le rôle manageRole dans la base de données des produits avec les privilèges suivants qui spécifient la base de données « managers » comme ressource :

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

Vous ne pouvez pas révoquer les actions « insert » ou « remove » d’une seule collection dans la base de données « managers ». Les opérations suivantes ne provoquent aucun changement dans le rôle :

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"
        ]
      }
    ]
  }
)

Pour révoquer les actions « insert » et/ou « remove » du rôle manageRole, vous devez faire correspondre exactement le document de ressource. Par exemple, l’opération suivante révoque uniquement l’action « remove » du privilège existant :

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

L’opération suivante retire plusieurs privilèges du rôle « executive » dans la base de données managers :

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

La commande rolesInfo renvoie des informations sur les privilèges et l’héritage pour les rôles spécifiés, y compris les rôles intégrés et définis par l’utilisateur. Vous pouvez également utiliser la commande rolesInfo pour récupérer tous les rôles ayant une portée sur une base de données.

Pour une exécution correcte, suivez cette syntaxe :

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

Pour retourner les informations d’un rôle de la base de données actuelle, vous pouvez spécifier son nom comme suit :

{ rolesInfo: "<rolename>" }

Pour renvoyer des informations sur un rôle à partir d’une autre base de données, vous pouvez mentionner le rôle avec un document qui mentionne le rôle et la base de données :

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

Par exemple, la commande suivante renvoie les informations d’héritage de rôle pour le rôle executive défini dans la base de données managers :

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

La commande suivante renvoie les informations sur l’héritage des rôles : accountManager sur la base de données sur laquelle la commande est exécutée :

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

La commande suivante renverra à la fois les privilèges et l’héritage des rôles pour le rôle « executive » tel que défini sur la base de données managers :

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

Pour mentionner plusieurs rôles, vous pouvez utiliser un tableau. Vous pouvez également mentionner chaque rôle dans le tableau sous forme de chaîne ou de document.

Vous ne devez utiliser une chaîne que si le rôle existe dans la base de données sur laquelle la commande est exécutée :

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

Par exemple, la commande suivante renverra des informations pour trois rôles sur trois bases de données différentes :

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

Vous pouvez obtenir à la fois les privilèges et l’héritage des rôles comme suit :

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

Intégrer des documents MongoDB pour de meilleures performances

Les bases de données de documents comme MongoDB vous permettent de définir votre schéma en fonction de vos besoins. Pour créer des schémas optimaux dans MongoDB, vous pouvez imbriquer les documents. Ainsi, au lieu de faire correspondre votre application à un modèle de données, vous pouvez construire un modèle de données qui correspond à votre cas d’utilisation.

Les documents imbriqués vous permettent de stocker des données similaires auxquelles vous accédez ensemble. Lors de la conception de schémas pour MongoDB, il est recommandé d’intégrer des documents par défaut. Utilisez les jointures et les références côté base de données ou côté application uniquement lorsqu’elles sont utiles.

Assurez-vous que la charge de travail peut récupérer un document aussi souvent que nécessaire. Dans le même temps, le document doit également disposer de toutes les données dont il a besoin. Il s’agit d’un élément essentiel pour les performances exceptionnelles de votre application.

Ci-dessous, vous trouverez quelques modèles différents pour intégrer des documents :

Modèle de document intégré

Vous pouvez l’utiliser pour intégrer des sous-structures complexes dans les documents avec lesquels elles sont utilisées. L’intégration de données connectées dans un seul document peut réduire le nombre d’opérations de lecture nécessaires pour obtenir des données. En règle générale, vous devez structurer votre schéma de manière à ce que votre application reçoive toutes ses informations requises en une seule opération de lecture. Par conséquent, la règle à garder à l’esprit ici est que ce qui est utilisé ensemble doit être stocké ensemble.

Modèle de sous-ensemble intégré

Le modèle de sous-ensemble intégré est un cas hybride. Vous l’utiliserez pour une collection séparée d’une longue liste d’éléments liés, où vous pouvez garder certains de ces éléments à portée de main pour les afficher.

Voici un exemple qui répertorie les critiques de films :

> 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"
}

Imaginez un millier de critiques similaires, mais vous ne prévoyez d’afficher que les deux plus récentes lorsque vous montrez un film. Dans ce scénario, il est logique de stocker ce sous-ensemble sous forme de liste dans le document du film :

> 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"}   
  ]   
}

En termes simples, si vous accédez régulièrement à un sous-ensemble d’articles similaires, assurez-vous de l’intégrer.

Accès indépendant

Vous pouvez vouloir stocker des sous-documents dans leur collection pour les séparer de leur collection mère.

Par exemple, prenez la gamme de produits d’une entreprise. Si l’entreprise vend un petit ensemble de produits, vous pourriez vouloir les stocker dans le document de l’entreprise. Mais si vous voulez les réutiliser dans plusieurs entreprises ou y accéder directement par leur unité de gestion des stocks (UGS), vous voudrez également les stocker dans leur collection.

Si vous manipulez ou accédez à une entité de manière indépendante, créez une collection pour la stocker séparément pour une meilleure pratique.

Listes non délimitées

Le stockage de courtes listes d’informations connexes dans leur document présente un inconvénient. Si votre liste continue à s’allonger de manière illimitée, vous ne devriez pas la placer dans un seul document. En effet, vous ne seriez pas en mesure de la supporter très longtemps.

Il y a deux raisons à cela. Premièrement, MongoDB a une limite sur la taille d’un document unique. Deuxièmement, si vous accédez au document à une fréquence trop élevée, vous obtiendrez des résultats négatifs dus à une utilisation incontrôlée de la mémoire.

En d’autres termes, si une liste commence à croître de manière illimitée, créez une collection pour la stocker séparément.

Modèle de référence étendu

Le modèle de référence étendu est semblable au modèle de sous-ensemble. Il optimise également les informations auxquelles vous accédez régulièrement pour les stocker sur le document.

Ici, au lieu d’une liste, il est exploité lorsqu’un document fait référence à un autre qui est présent dans la même collection. En même temps, il stocke également certains champs de cet autre document pour un accès facile.

Par exemple :

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

Comme vous pouvez le voir, « studio_id » est stocké afin que vous puissiez rechercher plus d’informations sur le studio qui a créé le film. Mais le nom du studio est également copié dans ce document pour plus de simplicité.

Pour intégrer régulièrement des informations provenant de documents modifiés, pensez à mettre à jour les documents dans lesquels vous avez copié ces informations lorsqu’elles sont modifiées. En d’autres termes, si vous accédez régulièrement à certains champs d’un document référencé, intégrez-les.

Comment surveiller MongoDB

Vous pouvez utiliser des outils de surveillance comme Kinsta APM pour déboguer les longs appels API, les requêtes de base de données lentes, les longues requêtes URL externes, pour n’en citer que quelques-uns. Vous pouvez même exploiter les commandes pour améliorer les performances de la base de données. Vous pouvez également les utiliser pour inspecter la santé de vos instances de base de données.

Pourquoi devriez-vous surveiller les bases de données MongoDB ?

Un aspect essentiel de la planification de l’administration des bases de données est la surveillance des performances et de la santé de votre cluster. MongoDB Atlas prend en charge la majorité des efforts d’administration grâce à ses capacités de tolérance aux pannes/de mise à l’échelle.

Malgré cela, les utilisateurs doivent savoir comment suivre les clusters. Ils doivent également savoir comment mettre à l’échelle ou ajuster ce dont ils ont besoin avant d’être confrontés à une crise.

En surveillant les bases de données MongoDB, vous pouvez :

  • Observer l’utilisation des ressources.
  • Comprendre la capacité actuelle de votre base de données.
  • Réagir et détecter les problèmes en temps réel pour améliorer votre pile d’applications.
  • Observer la présence de problèmes de performance et de comportements anormaux.
  • Vous aligner sur vos exigences en matière de gouvernance/protection des données et d’accords de niveau de service (SLA).

Mesures clés à surveiller

Lors de la surveillance de MongoDB, il y a quatre aspects clés que vous devez garder à l’esprit :

1. Mesures matérielles de MongoDB

Voici les principales mesures de surveillance du matériel :

Processeur normalisé

Il est défini comme le pourcentage de temps passé par le CPU sur le logiciel d’application qui maintient le processus MongoDB.

Vous pouvez le mettre à l’échelle dans une fourchette de 0 à 100 % en le divisant par le nombre de cœurs du CPU. Il inclut le CPU exploité par des modules tels que le noyau et l’utilisateur.

Un CPU de noyau élevé pourrait indiquer un épuisement du CPU via les opérations du système d’exploitation. Mais l’utilisateur lié aux opérations MongoDB peut être la cause principale de l’épuisement du CPU.

CPU système normalisé

Il s’agit du pourcentage de temps que le CPU a passé sur les appels système desservant ce processus MongoDB. Vous pouvez le mettre à l’échelle dans une fourchette de 0 à 100 % en le divisant par le nombre de cœurs de CPU. Il couvre également le CPU utilisé par des modules tels que iowait, user, kernel, steal, etc.

Un CPU utilisateur ou un noyau élevé pourrait indiquer un épuisement du CPU par des opérations MongoDB (logiciel). Un iowait élevé pourrait être lié à un épuisement du stockage entraînant un épuisement du CPU.

IOPS du disque

L’IOPS du disque est la moyenne des opérations d’E/S consommées par seconde sur la partition du disque de MongoDB.

Latence du disque

Il s’agit de la latence de lecture et d’écriture de la partition de disque en millisecondes dans MongoDB. Des valeurs élevées (>500ms) montrent que la couche de stockage peut affecter les performances de MongoDB.

Mémoire système

Utilisez la mémoire système pour décrire les octets de mémoire physique utilisés par rapport à l’espace libre disponible.

La métrique disponible indique approximativement le nombre d’octets de mémoire système disponibles. Vous pouvez l’utiliser pour exécuter de nouvelles applications, sans swapping.

Espace disque libre

Il s’agit du nombre total d’octets d’espace disque libre sur la partition du disque de MongoDB. L’Atlas MongoDB offre des capacités de mise à l’échelle automatique basées sur cette mesure.

Utilisation de l’espace de pagination

Vous pouvez exploiter un graphique d’utilisation du swap pour décrire la quantité de mémoire placée sur le dispositif de swap. Une métrique élevée dans ce graphique montre que le swap est utilisé. Cela montre que la mémoire est sous-provisionnée pour la charge de travail actuelle.

Mesures de connexion et de fonctionnement du cluster MongoDB

Voici les principales mesures pour les métriques d’opération et de connexion :

Temps d’exécution des opérations

La durée moyenne des opérations (opérations d’écriture et de lecture) exécutées sur la période d’échantillonnage sélectionnée.

Compteurs d’opérations

C’est le taux moyen d’opérations exécutées par seconde sur la période d’échantillonnage sélectionnée. Le graphique/la mesure Opcounters montre la répartition des opérations entre les types d’opérations et la vélocité pour l’instance.

Connexions

Cette mesure fait référence au nombre de connexions ouvertes à l’instance. Des pics ou des nombres élevés peuvent indiquer une stratégie de connexion sous-optimale, soit du côté du serveur non réactif, soit du côté du client.

Ciblage des requêtes et exécuteurs de requêtes

Il s’agit du taux moyen par seconde sur la période d’échantillonnage sélectionnée de documents numérisés. Pour les exécuteurs de requêtes, il s’agit de l’évaluation du plan de requête et des requêtes. Le ciblage des requêtes montre le rapport entre le nombre de documents scannés et le nombre de documents retournés.

Un ratio élevé indique des opérations sous-optimales. Ces opérations scannent beaucoup de documents pour en renvoyer une plus petite partie.

Numérisation et commande

Il décrit le taux moyen par seconde sur la période d’échantillonnage de requêtes choisie. Il renvoie des résultats triés qui ne peuvent pas exécuter l’opération de tri à l’aide d’un index.

Files d’attente

Les files d’attente peuvent décrire le nombre d’opérations en attente d’un verrou, que ce soit en écriture ou en lecture. Des files d’attente élevées pourraient dépeindre l’existence d’une conception de schéma non optimale. Cela pourrait également indiquer des chemins d’écriture conflictuels, poussant une forte concurrence sur les ressources de la base de données.

Mesures de réplication MongoDB

Voici les principales mesures pour la surveillance de la réplication :

Fenêtre Oplog de réplication

Cette mesure indique le nombre approximatif d’heures disponibles dans l’oplog de réplication du primaire. Si un secondaire accuse un retard supérieur à ce nombre, il ne peut pas suivre et aura besoin d’une resynchronisation complète.

Retard de réplication

Le retard de réplication est défini comme le nombre approximatif de secondes pendant lesquelles un nœud secondaire est en retard sur le primaire dans les opérations d’écriture. Un retard de réplication élevé indique que le secondaire a des difficultés à se répliquer. Cela pourrait avoir un impact sur la latence de votre opération, étant donné la préoccupation des connexions en lecture/écriture.

Hauteur de réplication

Cette mesure fait référence à la différence entre la fenêtre oplogue de la réplication primaire et le retard de réplication du secondaire. Si cette valeur va jusqu’à zéro, cela pourrait provoquer le passage d’un secondaire en mode RECOVERING.

Opcounters -repl

Opcounters -repl est défini comme le taux moyen d’opérations de réplication exécutées par seconde pour la période d’échantillonnage choisie. Avec l’opcounters -graph/metric, vous pouvez jeter un coup d’oeil à la vélocité des opérations et à la répartition des types d’opérations pour l’instance spécifiée.

Oplog Go/heure

Ceci est défini comme le taux moyen de gigaoctets d’oplog que le primaire génère par heure. Des volumes élevés et inattendus d’oplog peuvent indiquer une charge de travail en écriture très insuffisante ou un problème de conception de schéma.

Outils de surveillance des performances de MongoDB

MongoDB dispose d’outils d’interface utilisateur intégrés dans Cloud Manager, Atlas et Ops Manager pour le suivi des performances. Il fournit également quelques commandes et outils indépendants pour examiner des données plus brutes. Nous allons parler de certains outils que vous pouvez exécuter à partir d’un hôte qui a l’accès et les rôles appropriés pour vérifier votre environnement :

mongotop

Vous pouvez exploiter cette commande pour suivre le temps qu’une instance MongoDB passe à écrire et lire des données par collection. Utilisez la syntaxe suivante :

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

rs.status()

Cette commande renvoie l’état de l’ensemble de répliques. Elle est exécutée du point de vue du membre où la méthode est exécutée.

mongostat

Vous pouvez utiliser la commande mongostat pour obtenir un aperçu rapide de l’état de votre instance de serveur MongoDB. Pour un résultat optimal, vous pouvez l’utiliser pour surveiller une seule instance pour un événement spécifique car elle offre une vue en temps réel.

Exploitez cette commande pour surveiller les statistiques de base du serveur telles que les files d’attente de verrouillage, la ventilation des opérations, les statistiques de mémoire MongoDB et les connexions/réseau :

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

dbStats

Cette commande renvoie les statistiques de stockage pour une base de données spécifique, telles que le nombre d’index et leur taille, le total des données de collection par rapport à la taille de stockage, et les statistiques liées aux collections (nombre de collections et de documents).

db.serverStatus()

Vous pouvez exploiter la commande db.serverStatus() pour avoir un aperçu de l’état de la base de données. Elle vous donne un document représentant les compteurs métriques de l’instance actuelle. Exécutez cette commande à intervalles réguliers pour collationner les statistiques sur l’instance.

collStats

La commande collStats collecte des statistiques similaires à celles proposées par dbStats au niveau de la collection. Sa sortie consiste en un compte d’objets dans la collection, la quantité d’espace disque consommée par la collection, la taille de la collection et des informations concernant ses index pour une collection donnée.

Vous pouvez utiliser toutes ces commandes pour offrir des rapports et une surveillance en temps réel du serveur de base de données qui vous permettent de contrôler les performances et les erreurs de la base de données et d’aider à prendre des décisions éclairées pour affiner une base de données.

Comment supprimer une base de données MongoDB

Pour supprimer une base de données que vous avez créée dans MongoDB, vous devez vous y connecter via le mot-clé use.

Disons que vous avez créé une base de données nommée « Engineers ». Pour vous connecter à la base de données, vous utiliserez la commande suivante :

use Engineers

Ensuite, saisissez db.dropDatabase() pour vous débarrasser de cette base de données. Après exécution, voici le résultat auquel vous pouvez vous attendre :

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

Vous pouvez exécuter la commande showdbs pour vérifier si la base de données existe toujours.

Résumé

Pour tirer le maximum de valeur de MongoDB, vous devez avoir une bonne compréhension des principes de base. Il est donc essentiel de connaître les bases de données MongoDB comme sa poche. Pour cela, il faut d’abord se familiariser avec les méthodes de création d’une base de données.

Dans cet article, nous avons fait la lumière sur les différentes méthodes que vous pouvez utiliser pour créer une base de données dans MongoDB, suivies d’une description détaillée de quelques commandes MongoDB astucieuses pour vous permettre de garder le contrôle de vos bases de données. Enfin, nous avons terminé en discutant de la façon dont vous pouvez tirer parti des documents intégrés et des outils de surveillance des performances dans MongoDB pour vous assurer que votre flux de travail fonctionne au maximum de son efficacité.

Quel est votre avis sur ces commandes MongoDB ? Avons-nous omis un aspect ou une méthode que vous auriez aimé voir ici ? Faites-nous en part dans les commentaires !

Salman Ravoof

Salman Ravoof est un développeur web autodidacte, un écrivain, un créateur et un grand admirateur des logiciels libres. Outre la technologie, il est passionné par la science, la philosophie, la photographie, les arts, les chats et la nourriture. Apprenez-en plus sur son site web, et connectez-vous avec Salman sur X.