This document summarizes a presentation about migrating the popular Magento eCommerce platform from using a MySQL database to using MongoDB. It describes how Magento currently stores data in MySQL tables with one table per model. It then shows how the data can be migrated to a simpler, nested schema in MongoDB collections without changing Magento's core functionality. It demonstrates how custom resource models abstract the data access to make Magento continue working as before while using the new MongoDB backend.
2024: Domino Containers - The Next Step. News from the Domino Container commu...
Migrating One of the Most Popular eCommerce Platforms to MongoDB
1. Migrating One of the Most
Popular eCommerce
Platforms to MongoDB
MongoDB Munich 2013, October 14th
Aron Spohr, fashion4home GmbH, Berlin
aron.spohr@fashionforhome.de
3. What is Magento?
●
●
●
●
●
●
●
Open eCommerce platform
Serves all primary features of a Webshop
Written in PHP
Works on top of MySQL out of the box
Extensible architecture
Runs on over 180,000 sites
eBay owned since 2011
4. The Shopping Cart
● Quote
● Items
● Addresses
● one Model for each
● one MySQL-Table for each
6. as a developer in
// Loading a quote from database
$quote = Mage::getModel(‘sales/quote’)->load(560);
SELECT * FROM sales_quote WHERE quote_id=560;
// Loading a filtered collection of quote items from database
$items = $quote->getItemCollection();
$items->addFieldToFilter(‘product_id’, 1257);
$items->load();
SELECT * FROM sales_quote_item WHERE
quote_id=560 AND product_id=1257;
7. Persistence in
Application
every Model has
● a Resource Model to load/save one record from/to DB
● a Collection Model to load multiple records from DB
Model
Resource Model
DB
Collection Model
Model
Model
Model
8. Resource Model basics of
function load($object, $id) {
$stmt = “SELECT * FROM “ . $this->getTableName() .
” WHERE “ . $this->getIdFieldname() . ”=$id”;
$data = $sqlAdapter->fetchRow( $stmt );
$object->setData( $data );
}
9. Collection Model basics of
function load() {
$stmt = “SELECT * FROM “ . $this->getTableName() .
” WHERE “ . $this->renderFilters();
foreach($sqlAdapter->fetchRows( $stmt ) as $row) {
$object = new Object();
$object->setData($data);
$this->addItem($object);
}
}
10. Why should we change that?
● You don’t have to
● It always depends on your application
Reasons we had:
● Have more/other scalability options
● Make it easier to work with raw data
● Be more flexible with your data schema
● Learn more about the software you are using
11. Let’s get started
●
●
●
●
not change the way Magento works
a very simple, self-explainable data schema
make it easy to migrate old data
not lose any existing features
16. The path to our data
Name of Collection
/quote /item
Name of Array
in document
● Tells us where to find the data
● Is very similar to a table name
17. We rewire all Table names in
quote
/quote
quote_item
/quote/item
quote_address
/quote/address
18. The new Collection Model
$rows = $newAdapter->loadDataCollection(
$this->getTableName(),
$this->renderFilters() );
foreach($rows as $row) {
$object = new Object();
$object->setData($data);
$this->addItem($object);
}
20. as a developer in
// loading a filtered collection of quote items from database
$items = Mage::getModel(‘sales/quote_item’)->getCollection();
$items->addFieldToFilter(‘quote_id’, 560);
$items->addFieldToFilter(‘product_id’, 1257);
$items->load();
21. Loading a collection of things (filtered)
● This is not a relational database anymore
● Quote Items may not have a quote_id in our schema
loadDataCollection( ‘/quote/item’,
array( ‘quote_id’ => 560, ‘product_id’ => 1257) );
- no result
db.quote.find(
{ ‘item.quote_id’: 560, ‘item.product_id’: 1257 },
{ ‘item’: 1 } );
- no result
24. as a developer in
// load a single item from db, change qty, save it
$item = Mage::getModel(‘sales/quote_item’)->load(101);
$item->setQty(2);
$item->save();
// add a product to cart
$item = Mage::getModel(‘sales/quote_item’);
$item->setQuoteId(560)->setProductId(1566)->setQty(1);
$item->save();
25. Loading a single record
loadData( ‘/quote{quote_id:560}/item’, ‘item_id’, 100);
findOne({ ‘quote_id’: 560, ‘item.item_id’: 100}, {‘item.$’: 1});
loadData( ‘/quote/item’, ‘item_id’, 100);
loadData( ‘/quote{quote_id:$quote_id}/item’, ‘item_id’, 100);
findOne({ ‘item.item_id’: 100}, {‘item.$’: 1});
Result for all three
{ item_id: 100, product_id: 1257, qty: 1 }
27. The new resource model
function load($object, $id) {
$data = $adapter->loadData(
$this->getTablename(),
$this->getIdFieldname(),
$id);
$object->setData( $data );
}
28. The new resource model
function save($object) {
$id = $this->getNewId();
$data = $adapter->saveData(
$this->getTablename(),
$this->getIdFieldname(),
$id,
$object->getData());
$object->setId($id);
}
29. Migration of old data in
Application
create a simple application to
● load using the old resource model
● save using the new resource model
Old Resource Model
Model
New Resource Model
DB