Trees

MongoDB lends itself quite well to storing hierarchical data. This chapter will demonstrate some examples!

Full Tree in Single Document

<?php

/** @Document */
class BlogPost
{
    /** @Id */
    private $id;

    /** @String */
    private $title;

    /** @String */
    private $body;

    /** @EmbedMany(targetDocument="Comment") */
    private $comments = array();

    // ...
}

/** @EmbeddedDocument */
class Comment
{
    /** @String */
    private $by;

    /** @String */
    private $text;

    /** @EmbedMany(targetDocument="Comment") */
    private $replies = array();

    // ...
}

Retrieve a blog post and only select the first 10 comments:

<?php

$post = $dm->createQueryBuilder('BlogPost')
    ->selectSlice('replies', 0, 10)
    ->getQuery()
    ->getSingleResult();

$replies = $post->getReplies();

You can read more about this pattern on the MongoDB documentation page “Trees in MongoDB” in the Full Tree in Single Document section.

Parent Reference

<?php

/** @Document */
class Category
{
    /** @Id */
    private $id;

    /** @String */
    private $name;

    /**
     * @ReferenceOne(targetDocument="Category")
     * @Index
     */
    private $parent;

    // ...
}

Query for children by a specific parent id:

<?php

$children = $dm->createQueryBuilder('Category')
    ->field('parent.id')->equals('theid')
    ->getQuery()
    ->execute();

You can read more about this pattern on the MongoDB documentation page “Trees in MongoDB” in the Parent Links section.

Child Reference

<?php

/** @Document */
class Category
{
    /** @Id */
    private $id;

    /** @String */
    private $name;

    /**
     * @ReferenceMany(targetDocument="Category")
     * @Index
     */
    private $children = array();

    // ...
}

Query for immediate children of a category:

<?php

$category = $dm->createQueryBuilder('Category')
    ->field('id')->equals('theid')
    ->getQuery()
    ->getSingleResult();

$children = $category->getChildren();

Query for immediate parent of a category:

<?php

$parent = $dm->createQueryBuilder('Category')
    ->field('children.id')->equals('theid')
    ->getQuery()
    ->getSingleResult();

You can read more about this pattern on the MongoDB documentation page “Trees in MongoDB” in the Child Links section.

Array of Ancestors

<?php

/** @MappedSuperclass */
class BaseCategory
{
    /** @String */
    private $name;

    // ...
}

/** @Document */
class Category extends BaseCategory
{
    /** @Id */
    private $id;

    /**
     * @ReferenceMany(targetDocument="Category")
     * @Index
     */
    private $ancestors = array();

    /**
     * @ReferenceOne(targetDocument="Category")
     * @Index
     */
    private $parent;

    // ...
}

/** @EmbeddedDocument */
class SubCategory extends BaseCategory
{
}

Query for all descendants of a category:

<?php

$categories = $dm->createQueryBuilder('Category')
    ->field('ancestors.id')->equals('theid')
    ->getQuery()
    ->execute();

Query for all ancestors of a category:

<?php

$category = $dm->createQuery('Category')
    ->field('id')->equals('theid')
    ->getQuery()
    ->getSingleResult();

$ancestors = $category->getAncestors();

You can read more about this pattern on the MongoDB documentation page “Trees in MongoDB” in the Array of Ancestors section.

Materialized Paths

<?php

/** @Document */
class Category
{
    /** @Id */
    private $id;

    /** @String */
    private $name;

    /** @String */
    private $path;

    // ...
}

Query for the entire tree:

<?php

$categories = $dm->createQuery('Category')
    ->sort('path', 'asc')
    ->getQuery()
    ->execute();

Query for the node ‘b’ and all its descendants:

<?php
$categories = $dm->createQuery('Category')
    ->field('path')->equals('/^a,b,/')
    ->getQuery()
    ->execute();

You can read more about this pattern on the MongoDB documentation page “Trees in MongoDB” in the Materialized Paths (Full Path in Each Node) section.

Fork me on GitHub