有效地检查文件是否有孩子

时间:2015-01-14 08:25:06

标签: php mongodb mongodb-query doctrine-mongodb

我正在尝试使用Doctrine MongoDB构建一个延迟加载树。 我的文件结构如下:

/**
 * @ODM\Document(repositoryClass="CmsPage\Repository\PageRepository")
 */
class Page
{
    /**
     * @ODM\String
     * @var string
     */
    protected $title;

    /**
     * @ODM\ReferenceOne(targetDocument="CmsPage\Document\Page", inversedBy="children")
     * @ODM\Index
     * @var Page
     */
    protected $parent;

    /**
     * @ODM\ReferenceMany(
     *     targetDocument="CmsPage\Document\Page", mappedBy="parent",
     *     sort={"title": "asc"}
     * )
     * @var array
     */
    protected $children;

    /**
     * Default constructor
     */
    public function __construct()
    {
        $this->children = new ArrayCollection();
    }

    /**
     * @return ArrayCollection|Page[]
     */
    public function getChildren()
    {
        return $this->children;
    }

    /**
     * @param ArrayCollection $children
     */
    public function setChildren($children)
    {
        $this->children = $children;
    }

    /**
     * @return Page
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * @param Page $parent
     */
    public function setParent($parent)
    {
        $this->parent = $parent;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }
}

以下代码将检索给定页面的所有子项:

$page = $pageRepo->find('foo');
$children = [];

foreach ($page->getChildren() as $childPage) {
    $children[] = [
        'id' => $childPage->getId(),
        'slug' => $childPage->getSlug(),
        'leaf' => ($childPage->getChildren()->count() == 0)
    ];

这是按预期工作的,但会对每个子页面执行单独的查询以检查它是否为叶子。当处理具有大量子节点的大树时,它将不会有效。

我可以在我的Page文档中引入一个布尔isLeaf并在持久化时更新它。但这也意味着我必须在添加或删除子项时更新父项。

你有什么指针可以解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

我知道在MongoDB中测试数组不为空的最有效方法是搜索"第一个"使用"dot notation"$exists的数组中的元素。 query builder可以访问:

$qb = $dm->createQueryBuilder('Page')
    ->field('children.0')->exists(true);

这与shell中的相同:

db.collection.find({ "children.0": { "$exists": true } })

所以0是数组中第一个元素的索引,只有在该数组中有一些内容时才会出现。空数组与此条件不匹配。