Skip to content
intermediate Phase 35 · Models

Collections

AbstractCollection, filtering, sorting, loading, performance considerations, and collection patterns.

45m
0 problems
Topic Progress 0%

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?

Question 1 options

2. What is the N+1 query problem?

Question 2 options

3. How do you get the total count of a collection?

Question 3 options

4. What should be set BEFORE load() for performance?

Question 4 options

Flashcards

Question

What does addFieldToFilter() do?

Answer

Applies WHERE conditions to the collection

Question

How do you sort a collection?

Answer

$collection->setOrder('field', 'DESC')

Question

How do you paginate?

Answer

$collection->setPageSize(20)->setCurPage(2)->load()

Question

How do you join tables?

Answer

$collection->join(['alias' => 'table'], 'condition', ['columns'])

Question

What is the N+1 problem?

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()