2015-01-14 4 views
2

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) 
    ]; 

이 예상대로 작동하지만, 각 하위 페이지에 대한 별도의 쿼리를 실행합니다 잎인지 확인하십시오. 많은 자식 노드가있는 큰 트리를 처리 할 때 효율적이지 않습니다.

내 페이지 문서에 부울 isLeaf을 도입하고 지속될 때 업데이트 할 수 있습니다. 그러나 이것은 또한 자식을 추가하거나 제거 할 때 부모를 업데이트해야 함을 의미합니다.

이 문제를 해결하기위한 조언이 있습니까?

답변

3

배열이 비어 있지 않은지 테스트하기 위해 MongoDB에서 가장 효율적인 방법은 "dot notation"$exists을 사용하여 배열의 "첫 번째"요소의 존재를 검색하는 것입니다.

쉘이 동일한이다
$qb = $dm->createQueryBuilder('Page') 
    ->field('children.0')->exists(true); 

: 그래서

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

0 배열의 첫 번째 요소의 인덱스이며 때만 존재가 이에 대한 query builder에 접근이 해당 배열의 일부 내용입니다. 빈 배열이이 조건과 일치하지 않습니다.

+0

답변 해 주셔서 감사합니다. 나는 2 가지 염려가있다. 이렇게하면 적어도 하나 이상의 하위 페이지가 검색됩니다. 모든 페이지와 페이지에 어린이가 있는지 여부를 나타내는 플래그가 필요합니다. 또한이 방법은 여전히 ​​모든 페이지 imo에 대해 1 * n 쿼리를 트리거하지만, 먼저 테스트해야합니다. –

+0

[부모 참조] (http://docs.mongodb.org/manual/tutorial/model-tree-structures-with-parent-references/)를 사용하여 트리를 모델링했기 때문에이 방법을 사용할 수 없습니다. 내 문서는 MongoDB에'parent' 필드 만 있습니다. –

+0

@BramGerritsen 귀하의 모델은 어린이를 배열로 정의하지 않습니까? 그렇게 보입니다. 그것은 또한 논리적 인 일이 될 것입니다. –