Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sylius and MongoDB - It's not just changing connection strings

alcaeus
October 27, 2022

Sylius and MongoDB - It's not just changing connection strings

Migrating from MySQL to PostgreSQL in Sylius is easy - change the connection string and you’ll be good to go. But why isn’t it that easy if you want to use MongoDB? In this talk you’ll learn what sets schema design for MongoDB apart from relational databases, and we’ll take a look at what needs to be done to store Sylius data in MongoDB.

alcaeus

October 27, 2022
Tweet

More Decks by alcaeus

Other Decks in Programming

Transcript

  1. Relational databases Some say they are simple • Normalisation rules

    help us design “good” schemas • Have a primary key, add everything that depends on this primary key • If it’s not directly related to the primary key, extract it • ??? • Pro fi t!
  2. MongoDB Schemas are just as complicated • MongoDB is not

    “schemaless” • It has a schema, but it is fl exible • It avoids some constraints from relational databases • After all, they’re from the 1970s
  3. Example Address Book Data { "name": "alcaeus", "email": [ "<redacted>",

    "<redacted>" ], "phone": [ "<redacted>", "<redacted>" ] }
  4. Example Fancy Address Book Data { "name": "alcaeus", "email": [

    { "type": "work", "address": "<redacted>" }, { "type": "private", "address": "<redacted>" } ], "phone": [ { "type": "mobile", "number": "<redacted>" }, { "type": "home", "number": "<redacted>" } ] }
  5. Time for Queries Everybody loves queries, right? SELECT entry.* from

    entry JOIN email ON email.entry_id = entry.id WHERE email.address = 'something';
  6. Effects of Normalisation Does it help? • Need to join

    across tables to fi nd our main record • Only get main data • Multiple queries required to fetch rest of data • Alternative: complicated result preparation • How does this help?
  7. Sylius and MongoDB What’s the big problem? • Sylius uses

    Doctrine ORM • Doctrine ORM and Doctrine MongoDB ODM are very similar • Interfaces are shared, entities can be shared • How hard can it be?
  8. From ERD to Tables From Many to More CREATE TABLE

    sylius_channel (...); 
 
 CREATE TABLE sylius_product_option (...); 
 CREATE TABLE sylius_product_option_translation (...); 
 CREATE TABLE sylius_product_option_value (...); 
 CREATE TABLE sylius_product_option_value_translation (...); 
 CREATE TABLE sylius_product_attribute (...); 
 CREATE TABLE sylius_product_attribute_translation (…); 
 CREATE TABLE sylius_taxon (...); 
 CREATE TABLE sylius_taxon_translation (...); 
 CREATE TABLE sylius_product (...); 
 CREATE TABLE sylius_product_translation (...); 
 CREATE TABLE sylius_product_image (...); 
 CREATE TABLE sylius_product_attribute_value (...); 
 CREATE TABLE sylius_product_channels (...); 
 CREATE TABLE sylius_product_taxon (...); 
 CREATE TABLE sylius_product_options (...); 
 CREATE TABLE sylius_product_variant (...); 
 CREATE TABLE sylius_product_variant_option_value (...); 
 CREATE TABLE sylius_channel_pricing (...);
  9. From Tables to Collections Making use of advanced schema types

    • References point to related data • Embedded documents include all related data • Could be used in relational databases (jsonb / complex types) • Advantages to both • It’s important to understand when to choose which
  10. Taxons Embedded Translations { "_id": "...", "code": "...", "translations": {

    "en": { "slug": "hardware", "name": "Hardware", "description": "..." }, "de": { "slug": "hardware", "name": "Hardware", "description": "..." } } }
  11. Taxons Simpli fi ed Translations { "_id": "...", "code": "...",

    "slug": { "en": "hardware", "de": "hardware" }, "name": { "en": "Hardware", "de": "Hardware" }, "description": { "en": "...", "de": "..." } }
  12. Options Embedded Values { "_id": "...", "code": "length", "name": {

    "en": "Length", "de": "Länge" }, "values": [ { “code": "length-1-m“, "value": { "en": "3 ft", "de": "1 m" } } ] }
  13. Product ODM References { "_id": "...", "code": "lightning-cable", "options": [

    { "ref": "sylius_product_option", "id": "..." }, { "ref": "sylius_product_option", "id": "..." }, { "ref": "sylius_product_option", "id": "..." } ] }
  14. Referencing or embedding? Is there another way? • Example: linking

    product variants and their option values • We don’t own the data, so we should use references • We don’t want to join, so embedded data would be best • We can’t reference an embedded document • Why not do both?
  15. Product Hybrid References { "_id": "...", "code": "lightning-cable", "options": [

    { "ref": "sylius_product_option", "id": "...", "code": "length", "name": { "en": "Length", "de": "Länge" } } ] }
  16. Product Variant Hybrid References { "_id": "...", "code": "lightning-cable-1-m", "position":

    0, "options": { "length": { "code": "length-1-m", "value": { "en": "3 ft", "de": "1 m" } } } }
  17. Product Variant Embed All The Variants? { "_id": "...", "code":

    "lightning-cable", "options": [ ... ], "variants": [ { "code": "lightning-cable-1-m", "options": { "length": { "code": "length-1-m", "value": { "en": "3 ft", "de": "1 m" } } } } ] }
  18. Transactions Quick facts • MongoDB is ACID compliant • You

    can run multi-document transactions • No nested transactions • Good schema design can help you avoid them • Doctrine MongoDB ODM doesn’t support them
  19. Transactions In a nutshell • Start transaction • Do your

    business logic • Commit transaction • (Or abort if you’ve decided otherwise) • Rollback on error
  20. Transactions Retry Failed Commits $session->startTransaction(); // Complex database logic here

    while (1) { try { $session->commitTransaction(); } catch (RuntimeException $e) { if ( $e->getCode() !== 50 /* MaxTimeMSExpired */ && $e->hasErrorLabel('UnknownTransactionCommitResult') ) { // Retry committing the transaction continue; } throw $e; } }
  21. Transactions Retry Failed Transactions while (1) { $session->startTransaction(); // Complex

    database logic here while (1) { try { $session->commitTransaction(); } catch (RuntimeException $e) { if ( $e->getCode() !== 50 /* MaxTimeMSExpired */ && $e->hasErrorLabel('UnknownTransactionCommitResult') ) { // Retry committing the transaction continue; } if ( $e->hasErrorLabel('TransientTransactionError') ) { // Restart transaction continue 2; } throw $e; } } }
  22. Transactions Keep It Simple $doComplexDatabaseLogic = function (Session $session): void

    { // Complex database logic here }; $session = $client->startSession(); \MongoDB\with_transaction( $session, $doComplexDatabaseLogic, );
  23. Transactions With Doctrine MongoDB ODM $session = $client->startSession(); \MongoDB\with_transaction( $session,

    function (Session $session) use ($documentManager): void { $documentManager->flush(['session' => $session]); } );
  24. Ecosystem Updates Doctrine MongoDB ODM • Support transactions in UnitOfWork

    • Support new update mechanisms • Support hybrid references • Support updating hybrid references
  25. Ecosystem Updates Doctrine Extensions • Update Translation extension to leverage

    embedded documents • Update Tree extension to support nested set in ODM • Update Sortable extension to support ODM
  26. Ecosystem Updates Sylius • Create mapping fi les for Doctrine

    MongoDB ODM • Create repositories and rewrite queries