Collection Structure
Collections represent sets of models for querying and iteration.
Basic collection:
<?php
namespace Vendor\Blog\Model\ResourceModel\Post;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
protected $_idFieldName = 'entity_id';
protected function _construct()
{
$this->_init(
\Vendor\Blog\Model\Post::class,
\Vendor\Blog\Model\ResourceModel\Post::class
);
}
}
Using collection:
// Load all posts
$collection = $this->postCollectionFactory->create();
$collection->load();
foreach ($collection as $post) {
echo $post->getTitle();
}
// Count items
echo $collection->count();
// Get first item
$firstPost = $collection->getFirstItem();
// Get last item
$lastPost = $collection->getLastItem();
// Convert to array
$array = $collection->toArray();
Collection factory:
// Inject collection factory
public function __construct(
\Vendor\Blog\Model\ResourceModel\Post\CollectionFactory $collectionFactory
) {
$this->collectionFactory = $collectionFactory;
}
// Create collection
$collection = $this->collectionFactory->create();
Filtering Collections
Apply filters to narrow down collection results.
Basic filtering:
$collection = $this->postCollectionFactory->create();
// Filter by field
$collection->addFieldToFilter('status', 1);
// Filter by multiple values
$collection->addFieldToFilter('status', ['in' => [1, 2, 3]]);
// Filter with conditions
$collection->addFieldToFilter('title', ['like' => '%keyword%']);
// Filter by date
$collection->addFieldToFilter('created_at', [
'from' => '2024-01-01',
'to' => '2024-12-31'
]);
Filter operators:
'eq' => = (default)
'neq' => !=
'like' => LIKE
'in' => IN
'nin' => NOT IN
'gt' => >
'gteq' => >=
'lt' => <
'lteq' => <=
'null' => IS NULL
'notnull' => IS NOT NULL
Multiple filters:
$collection->addFieldToFilter('status', 1)
->addFieldToFilter('category_id', 5)
->addFieldToFilter('created_at', ['from' => '2024-01-01']);
Filter with OR condition:
$collection->getSelect()->where(
'status = ? OR featured = ?',
[1, 1]
);
Sorting and Pagination
Order results and paginate collections.
Sorting:
$collection = $this->postCollectionFactory->create();
// Sort by field
$collection->setOrder('created_at', 'DESC');
// Sort by multiple fields
$collection->setOrder('position', 'ASC')
->setOrder('created_at', 'DESC');
// Add sort order
$collection->addOrder(
$this->resource->getSelect()->order('title ASC')
);
Pagination:
$collection = $this->postCollectionFactory->create();
// Set page size
$collection->setPageSize(20);
// Set current page
$collection->setCurPage(2);
// Load page
$collection->load();
// Get total count
$total = $collection->getSize();
// Get pagination info
$lastPage = $collection->getLastPageNumber();
$currentPage = $collection->getCurPage();
Efficient pagination:
// BAD: Load all, then paginate
$collection->load();
$collection->setCurPage(2);
$collection->setPageSize(20);
// GOOD: Set pagination before load
$collection->setPageSize(20)
->setCurPage(2)
->load();
Collection Performance
Performance considerations for collections.
N+1 query problem:
// BAD: N+1 queries
$collection = $this->postCollectionFactory->create();
$collection->load();
foreach ($collection as $post) {
// This triggers a query for EACH post
$author = $this->authorFactory->create()->load($post->getAuthorId());
echo $author->getName();
}
// GOOD: Join or use joinField
$collection->join(
['author' => 'vendor_blog_author'],
'author.entity_id = main_table.author_id',
['author_name' => 'name']
);
Join methods:
// Join with another table
$collection->join(
['alias' => 'table_name'],
'alias.foreign_key = main_table.primary_key',
['column_alias' => 'column_name']
);
// Left join
$collection->getSelect()->joinLeft(
['alias' => 'table_name'],
'alias.foreign_key = main_table.primary_key',
['column_alias' => 'column_name']
);
Performance tips:
1. Use setPageSize() before load()
2. Avoid loading all items when count is needed
3. Use join() instead of lazy loading
4. Use addFieldToFilter() over getSelect()->where()
5. Limit fields with addFieldToSelect()
Select specific fields:
// Load all fields (default)
$collection->addFieldToSelect('*');
// Load specific fields
$collection->addFieldToSelect(['entity_id', 'title', 'status']);
// Add computed field
$collection->getSelect()->columns(
['total' => 'COUNT(*)']
);
Quiz
1. What does addFieldToFilter() do?
2. What is the N+1 query problem?
3. How do you get the total count of a collection?
4. What should be set BEFORE load() for performance?
Flashcards
Question
What does addFieldToFilter() do?
Click to reveal answer
Answer
Applies WHERE conditions to the collection
Question
How do you sort a collection?
Click to reveal answer
Answer
$collection->setOrder('field', 'DESC')
Question
How do you paginate?
Click to reveal answer
Answer
$collection->setPageSize(20)->setCurPage(2)->load()
Question
How do you join tables?
Click to reveal answer
Answer
$collection->join(['alias' => 'table'], 'condition', ['columns'])
Question
What is the N+1 problem?
Click to reveal answer
Answer
Executing a query for each item in a loop instead of using JOIN
Revision Notes
Key Takeaways
- 1. Collections represent sets of models for querying
- 2. addFieldToFilter() applies WHERE conditions
- 3. setOrder() sorts results; setPageSize()/setCurPage() for pagination
- 4. Join related tables to avoid N+1 queries
- 5. Set filters, order, and pagination before load()
- 6. getSize() returns count without loading items
Interview Tips
- • Explain how to filter and sort collections
- • Describe the N+1 query problem and solutions
- • Know efficient pagination techniques
- • Discuss collection joining patterns
Cheat Sheet
Collections Cheat Sheet
Basic:
$collection = $this->collectionFactory->create();
$collection->load();
Filter:
$collection->addFieldToFilter('status', 1);
$collection->addFieldToFilter('title', ['like' => '%keyword%']);
Sort:
$collection->setOrder('created_at', 'DESC');
Paginate:
$collection->setPageSize(20)->setCurPage(2)->load();
Join:
$collection->join(['a' => 'table'], 'a.id = main_table.id', ['col' => 'col']);
Performance: Set filters/order/pagesize BEFORE load()