+
]
>
}
<

NOUS LES DEVS

Stockage BDD

A la conquête du jeu vidéo partie 7

Niveau : intermédiaire
</> </> </>

MongoDB

Je vais bientôt devoir afficher la liste des maps disponibles, et ça serait peut-être pas mal de les stocker dans mongoDB, car une map contient une grosse quantité de données.

Et il y a un truc vraiment cool avec mongoDB, c’est que je peux directement stocker un gros tableau et faire des traitements dessus. C’est l’une des raisons pour laquelle j’ai choisi ce SGBDD.

J’ouvre un shell mongoDB, je crée vite fait bien fait une DB « warsio » et une collection « maps » (c’est l’équivalent d’une table dans MySQL) et j’ajoute ma première map.

#je switch de DB même si elle n'existe pas
use warsio
> switched to db warsio

#J'ajoute une map, ce qui va créer la collection automatiquement
db.maps.insert({nom:"Intro",nbr_joueur:2, map : [ [ "086", "105", "084", "084", "084", "084", "107", "084", "084", "084", "084", "084", "084", "084", "104" ], [ "105", "085", "022", "168", "150", "005", "008", "005", "002", "022", "168", "159", "022", "159", "073" ], [ "075", "022", "022", "168", "149", "168", "063", "022", "021", "157", "022", "022", "140", "159", "073" ], [ "075", "047", "047", "001", "018", "058", "096", "060", "021", "022", "025", "022", "021", "159", "073" ], [ "075", "022", "022", "021", "022", "073", "105", "085", "021", "047", "025", "047", "149", "022", "073" ], [ "075", "158", "150", "018", "157", "083", "085", "168", "151", "005", "005", "005", "020", "047", "073" ], [ "075", "158", "139", "022", "022", "022", "022", "168", "168", "101", "058", "059", "024", "078", "106" ], [ "095", "060", "158", "158", "022", "022", "022", "022", "022", "022", "073", "085", "022", "022", "073" ], [ "105", "108", "059", "060", "025", "157", "025", "168", "157", "101", "008", "022", "157", "157", "073" ], [ "095", "094", "086", "095", "059", "059", "059", "059", "059", "059", "096", "059", "059", "059", "094" ] ] });
> WriteResult({ "nInserted" : 1 })

Processus non bloquant

Juste avant de lancer la méthode init() au niveau de mon serveur node.js, j’appelle la méthode start_db() que je viens d’ajouter dans ma classe link.

Et là il y a une notion très importante à comprendre dans le fait que node.js est non bloquant. Dans l’exemple ci-dessous, le serveur HTTP démarre avant le serveur MongoDB car celui-ci a mis trop de temps pour se lancer. Node.js a donc suspendu la tâche et l’a reprise après.

Node.js est single thread (un seul processus), c’est-à-dire qu’il exécute ce qu’il y a dans la pile. Excepté qu’il est capable de passer à la tâche suivante et de traiter celle qui prennent le plus de temps « plus tard ».

start_db(){
	lib_mongodb.MongoClient.connect( this.server_config.url_mongo_server , (err, db) => {
		if (err) {
			e("Unable to start DB : ",err);
		}else{
			e("/***********	MongoDB is started	***********/");
			this.mongodb = db;
		}
	});
}
//start DB
this.start_db()
//initialisation http
this.init();	

Promesse

Socket.io est tellement rapide pour établir la connexion que le joueur est déjà connecté avant même que la DB soit disponible, ce qui est un peu con car je ne peux même pas lui envoyer le nom des maps… Pour régler le problème, je vais utiliser une petite promesse JavaScript.

start_db(){
	return new Promise((resolve, reject) => {
		lib_mongodb.MongoClient.connect( this.server_config.url_mongo_server , (err, db) => {
			if (err) {
				e("Unable to start DB : ",err);
			}else{
				this.mongodb = db;
				resolve(true);
			}
		});
	});
}

Et bien évidemment, je lance l’init() au retour de la promesse.

this.start_db().then( (response) => {
	//initialisation http
	this.init();	
});

Récupération des maps

Maintenant que j’ai une connexion à MongoDB, je vais pouvoir récupérer la liste des maps et les stocker au niveau de mon serveur, enfin… Au niveau de mon application quoi. Donc je crée une petite méthode get_list_map() qui se chargera de retourner la liste des maps !

Et là je suis super dégouté, car j’ai mis au moins une heure à comprendre… En fait, le forEach sur le résultat ne marchait pas ! Il fallait utiliser un toArray() pour pouvoir traiter le tableau, en fait ce n’est pas exactement la même chose que dans le shell, mais c’est pas grave, le principal c’est que ça marche.

get_list_map(){
	return this.mongodb.collection('maps').find({ nbr_joueur : { $gt : 0 } }).toArray();		
}

Haaaaaa oui… La méthode est asynchrone, donc c’est pareil que la connexion, je dois reclaquer une promesse sinon le client sera connecté avant d’avoir obtenu les maps. Bon, l’avantage c’est que la méthode en retourne une automatiquement, donc un p’tit chainage de promesses et le tour est joué ! Tu aimes ça !! Avoue !!

Au passage, je sauvegarde les maps dans une variable.

//demarrage de la DB
this.start_db().then( () => this.get_list_maps() ).then( (response) => {
	this.maps = response;
	//initialisation http
	this.init();	
});

04/06/2016

Yann Vangampelaere - nouslesdevs -

NOUS LES DEVS

Vous aimez ce que je fais ? Vous voulez que j'en fasse plus ? dans le développement du blog.