Laravel : utiliser Big Query avec Eloquent

Laravel vient avec son ORM: un outil de gestion de bases de données nommé Eloquent. Celui-ci est super pratique lorsqu’on utilise une base de données standard type mySQL. Il s’occupe de générer des objets à partir des enregistrements en base, des mises à jour, de la pagination… mais lorsque notre base se porte sur Big Query, les choses se compliquent.

Big Query:

Pour ceux qui ne connaissent pas Big Query. Sachez que c’est une base de données utilisée sur le cloud Google. Elle permet d’ingérer des To de données et d’exécuter des requêtes ultra rapidement.

Les librairies existantes:

Il n’y a pas foule d’outils entre PHP et Big Query. La librairie la plus intéressante que j’ai trouvée est celle-ci: https://github.com/prologuetech/laravel-big mais elle possède pas mal de problèmes. Je suis parti sur leur travail, et j’ai ajouté pas mal de fonctions utiles.
Voyons ensemble les problèmes et leurs solutions.

Les problèmes de compatibilité Big Query/Eloquent:

Les types de champs dans Big Query sont différents de ceux de MySQL. Il faut donc effectuer des correspondances. Pour cela, nous avons la fonction flipModel qui permet de convertir des objets Eloquent en schema Big Query. En revanche, l’inverse n’existe pas. Impossible de restituer une requête BQ sous forme d’objets Eloquent (j’ai donc créé la fonction unflip).

Lorsqu’on envoie une requête dans BQ, il faut qu’elle soit complète (SQL + valeurs des champs). Il n’y a pas d’option bind comme on peut faire depuis toujours avec le PDO. Bienvenue dans le retour de l’injection SQL. J’ai donc ajouté une fonction BindQuery qui remédie à cela.

A noter que les noms des tables BQ et mySQL différent. En effet une table BQ appartient à un projet et à un dataset, il faut donc écrire le nom complet sous cette forme:
select * from projet.dataset.produits.
J’ai donc ajouté des replaces pour que ceci soit transparent (il y a surement mieux mais bon…)

Lorsqu’on recherche une donnée en BQ avec un like celui ci est sensible à la casse. Il faudrait lui ajouter un paramètre qu’on ne peut pas gérer en ELOQUENT. J’ai donc ajouté un tableau des paramètres like afin de leur ajouter un LOWERCASE automatiquement.

Enfin, lorsqu’on fait un order By, Eloquent se charge de faire des aggrégats, ce qui n’existe pas en BQ. J’ai donc ajouté une fonction BindCountQuery pour s’occuper de récupérer le total de mes produits. Attention à bien rajouter l’option useQueryCache si vous souhaitez profiter du cache:

$products = Product::all();
$arrLikeFields[] = "title";
$products = $products->where("title","LIKE","%".$q."%");
$big = new Big();
$big->options["useQueryCache"] = true;
$sql = $big->bindQuery($query->orderBy("updated_at"), array("products"),15, $currentPage, $arrLikeFields);
$products = Big::unflipModel(new Product(), $big->run($sql));
$products = new LengthAwarePaginator($products, $totalProducts, 15, $currentPage, ['path'=>url($url)]);

Insertions et suppressions:

Lorsqu’on insert des données en Laravel, on fait objet.save, et on ne s’occupe plus du reste. Chez Bq, on paye à la requête, donc si on peut lui envoyer plusieurs milliers de lignes en 1 fois, il faut pas se priver. Pour cela, je fais un tableau de 5000 produits et je les inserts comme cela:

$rows = $big->prepareData($products);
$big->insert($table, $rows);

Sachez quand même qu’il faudra compter un bon 30 minutes avant de pouvoir les modifier/supprimer.

Conclusion:

Si vous souhaitez télécharger ma librairie celle-ci est disponible ici: https://github.com/ynizon/laravel-big ou via

composer require ynizon/big

Comme je ne suis pas encore sur de mes modifications à 100 %, j’ai préféré faire un fork que contacter l’auteur pour faire des mises à jour. On verra plus tard pour faire un merge…
Plus j’avance, plus je complète, mais je suis déjà assez content de mes résultats pour les publier. 🙂

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.