Sytuacja kobiet w IT w 2024 roku
2.11.20206 min
Alex Renoki

Alex RenokiFounder & DeveloperRenoki Co.

Jak zacząć z MongoDB na Laravelu

Sprawdź, jak zacząć pracę z systemem zarządzania bazami danych o nazwie MongoDB na Laravelu.

Jak zacząć z MongoDB na Laravelu

Jakiś czas temu opublikowałem następujący artykuł: Konfiguracja MongoDB dla Laravela w ploi.io. ploi.io jest świetne, gdy musisz dokonać nieskomplikowanego deploymentu aplikacji na produkcję. Tym razem jednak porozmawiamy o MongoDB na Laravelu. NoSQL (MongoDB) nie jest zbyt popularne, jeżeli chodzi o Laravela, ponieważ niewielu używa tam Mongo zamiast SQL. SQL jest w zasadzie wbudowane w Laravela i można dzięki niemu szybko zrozumieć, jak działają tam bazy danych. 

Jeżeli interesują Cię wady i zalety NoSQL, to zachęcam do zapoznania się z wyżej wspomnianym artykułem. Tym razem po krótce opiszę każdą wadę i zaletę wspomnianą w poprzednim artykule, podając tym samym przykłady na temat tego, jak różne rzeczy działają, jak używać ich lokalnie i jaki mają wpływ na środowisko produkcyjne. 

Zaczynając jednak od początku — musisz znać Laravel Eloquent ORM, aby móc zrobić cokolwiek więcej. 

Warunki wstępne i działanie lokalne

Zdecydowanie musisz mieć MongoDB na swojej maszynie. Zachęcam do uruchomienia Valet albo Homestead na swoim lokalnym urządzeniu, ponieważ tak jest łatwiej. Jeżeli chodzi o MongoDB, to ja pracowałem tylko z Homestead. 

Jeżeli możesz pracować z Homestead, dodaj mongodb: true do swojego pliku Homestead.yaml. Oto moja konfiguracja dla Homestead: 

ip: 192.168.10.13
memory: 4096
cpus: 2
mongodb: true
mariadb: true
provider: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
  - ~/.ssh/id_rsa
folders:
  -
    map: 'C:\Laravel\homestead'
    to: /home/vagrant/code
sites:
  -
    map: homestead.test
    to: /home/vagrant/code/public
    php: "7.2"
    schedule: true
databases:
  - homestead
name: homestead
hostname: homestead


Zachęcam również do używania komendy vendor/bin/homestead make zamiast kopiowania konfiguracji, którą podałem jako przykład, ponieważ ścieżka do folderu powinna być automatycznie generowana przez powyższą komendę. Chciałem Wam po prostu pokazać, że mam u siebie mongodb: true.

Następnie musisz ponownie uruchomić provisioning na swojej maszynie albo odpalić Homestead z --provision, jeśli nie używało się wcześniej up

Możesz się do niej dostać przez localhost (jako host) i homestead / secret (jako użytkownik i hasło).

Eloquent ORM dla NoSQL

Ten pakiet MongoDB jest całkiem popularny. Być może istnieje więcej pakietów, które obsługują NoSQL, ale najbardziej ufamy takim, które buduje społeczność. Odpalałem go również samemu na produkcji i do tej pory nie miałem żadnych problemów.  Konfiguracja jest prosta, jeśli przeczyta się dokumentację — pomoże Ci ona zainstalować nasz pakiet przez Composer i skonfigurować sterowniki bazy danych. Skupimy się tutaj jednak na ważnych rzeczach. 

Nasz pakiet oferuje model Moloquent. Jest to model Eloquent, ale skonstruowany specjalnie dla Mongo. Jeśli pracowało się trochę z ORM, to pewnie następujący widok nie jest Ci obcy:

class Post extends Model
{
   //
}


W tym przypadku nie będziemy rozszerzać klasy Model, czyli podstawowego modelu od Laravela.

use Jenssegers\Mongodb\Eloquent\Model;
class Post extends Model
{
  //
}


SQL działa z tabelami, a NoSQL z kolekcjami. Zamiast zmiennej $table mamy zmienną $collection. Warto również zauważyć, że klucza podstawowego nie można ustawić za pomocą $primaryKey, a $incrementing jest niedostępne. Warto też określić, że model należy do połączenia mongodb, które stworzyliśmy wcześniej:

use Jenssegers\Mongodb\Eloquent\Model;
class Post extends Model
{
   protected $connection = 'mongodb';
}


Musisz pogodzić się z faktem, że MongoDB automatycznie przypisuje klucze do dokumentów (odpowiednik wierszy w SQL). Aby otrzymać dostęp do głównego klucza dokumentu, musisz mieć taką samą nazwę atrybutu, jak w podstawowym modelu. 

echo 'The post ID is: '. $post->_id;
echo 'The post ID is '. $post->id; // they both work


find() używa pola klucza głównego, aby zwrócić wynik:

$post = Post::find('517c43667db388101e00000f');

Prawie całkowity brak schematów

W NoSQL nie mamy schematów do zdefiniowania. Możemy skorzystać z migracji, aby zdefiniować indeksy, unikalne pola i inne pola specyficzne dla mongo:

Schema::create('posts', function ($collection) {
   $collection->index('slug');
   $collection->unique('slug');
});

Proces migracji wygląda tam tak samo. Aby odpalić migracje, upewnij się, że domyślne ustawienie sterowników (zmienna DB_CONNECTION env) jest ustawione na mongodb. 

php artisan migrate


Co możemy zrobić w przypadku, gdy chcemy odpalić zarówno SQL, jak i NoSQL w tym samym projekcie:

  • przenieś migracje SQL do folderu znajdującego się wewnątrz folderu z migracjami. Ja go nazwę mysql
  • Wszystkie modele, które działają z czymś innym niż domyślnym sterownikiem bazy danych powinny rozszerzy właściwy model


Uruchamianie migracji powinno się odbywać dwojako, jeśli chodzi o uruchomienie lokalne albo na produkcji. Dla sterownika domyślnego (tj. gdy DB_CONNECTION jest ustawione na mongodb):

php artisan migrate


Dla drugiego sterownika (np. dla MySQL):

php artisan migrate --database=mysql --path=database/migrations/mysql/

Uwierzytelnianie użytkowników za pomocą MongoDB

Duży problem, który napotkałem z MongoDB, dotyczył elementu User. Rozszerza on model Authenticatable. MongoDB nie obsługuje domyślnego modelu oferowanego przez Laravela, więc będziemy musieli użyć tego, który jest dołączony do pakietu:

use Jenssegers\Mongodb\Auth\User as Authenticatable;
class User extends Authenticatable
{
   //
}


Jeśli chcesz używać Laravel Passport z MongoDB, upewnij się, że używasz designmynight/laravel-mongodb-passport. Zapewni Ci to kolejną klasę Authenticatable, która wykona zadanie za Ciebie!

NoSQL = NoJoins 

NoSQL jest z kilku powodów lepszy od SQL: lepsza elastyczność, szybkość, skalowalność i integralność. Jedynym minusem jest to, że nie mamy odpowiednika join. Nie możemy użyć trzeciego zbioru do połączenia danych między dwoma innymi zbiorami. Jednak w naszym pakiecie jest kilka niespodzianek. 

Na przykład, relacja belongsToMany wyglądałaby następująco:

class User extends Model
{
   public function roles()
   {
      return $this->belongsToMany('App\Role');
   }
}
class Role extends Model
{
   public function users()
   {
      return $this->belongsToMany('App\User');
   }
}


Niezależnie od tego, czy próbujesz uzyskać dostęp do $user->roles, czy $role->users, to będziesz potrzebować trzeciej tabeli o nazwie role_user, która przechowuje dane.

W tym przypadku MongoDB robi coś paskudnego: umożliwia many-to-many, ale nie potrzebuje trzeciej tabeli — po prostu przechowuje identyfikatory we własnych modelach. Upewnij się, że jeśli chcesz ustawić niestandardowe klucze obce, ustaw drugi parametr funkcji belongsToMany na null.

class User extends Model
{
   public function roles()
   {
      return $this->belongsToMany('App\Role', null, 'users_ids', 'roles_ids');
   }
}
class Role extends Model
{
   public function users()
   {
      return $this->belongsToMany('App\User', null, 'roles_ids', 'users_ids');
   }
}
$role = Role::named('admin')->first();
$user->attach($role);
$role->attach($user);


Po zakończeniu powyższego otrzymasz coś takiego:

Dokument User wygląda następująco:

{
   "_id": "user_id_here",
   "username": "dummy",
   ...,
   "roles_ids": [
     "role_id_here"
   ]
}


Dokument Role wygląda następująco:

{
   "_id": "role_id_here",
   "name": "administrator",
   ...,
   "users_ids": [
     "user_id_here"
   ]
}


Reszta innych relacji, wyłączając morphToMany, działa tak samo, jak w SQL.

Schemat daje Ci możliwość zabawy

Dopóki NoSQL nie ma schematów, to możemy je zdefiniować podczas pracy z danymi, prawda? W MongoDB możemy wyrzucać pola, kiedy tylko chcemy.

Oto nasz dokument: 

{
   "_id": "...",
   "name": "John",
   "password": "...",
   "old_field1": "value1",
   "old_field2": "value2",
}


Jeśli chcemy wyrzucić trochę pól, to możemy to zrobić przy użyciu metody drop:

$john = User::where('name', 'John')->first();
$john->drop('old_field1');
// or
$john->drop(['old_field1', 'old_field2']); // works with more


W końcu usunie ona pole z naszego dokumentu:

{
   "_id": "...",
   "name": "John",
   "password": "..."
}

Wprowadzanie na produkcję 

Od jakiegoś już czasu używam MongoDB na produkcji. Prawda jest taka, że przy podstawowym użyciu ORM z małą konfiguracją MongoDB, tak jak opisałem to w artykule wspomnianym na początku, działa to bezproblemowo.

MongoDB jest szybki i niezawodny nawet w przypadku aplikacji o dużym natężeniu ruchu. Średnio zużywa około 4 GB pamięci RAM przy około 600 milionach odczytów, zapisów i usuwaniu dokumentów w ciągu całego miesiąca, przy średniej łącznej liczbie 600 zapisów i odczytów na sekundę.

Nie polecam używania go do cache'owania — ilekroć chcesz to robić, pamiętaj tylko o używaniu memory over disk — zapewnia to mniejsze tarcie i większą szybkość dostępu i pisania.


Oryginał tekstu w języku angielskim możesz przeczytać tutaj.

<p>Loading...</p>