簡體   English   中英

如何使用mongodb從doctrine ODM中引用的文檔數組中刪除文檔

[英]How to delete document from a referenced array of documents in doctrine ODM with mongodb

我有一個php對象映射到具有結構的mongodb文檔(稱為Node)

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;

class Node{
    /**
    * @MongoDB\Id
    */
    protected $id;

    /**
    * @MongoDB\String
    */
    protected $domain;

    /**
    * @MongoDB\ReferenceMany(targetDocument="NodeItem",cascade=     
    * {"persist"},simple="true")
    */
    protected $items = array();

    //getter and setters below
}

一個名為NodeItem的引用文檔,

class NodeItem {

  /**
  * @MongoDB\Id
  */
  protected $id;

  /**
  * @MongoDB\String
  */
  protected $name;

  /**
   * @MongoDB\ReferenceOne(targetDocument="Node", cascade={"persist"},    
   *  simple="true")
   */
   protected Node;

   //setter and getters 
}

正如“節點”上面的注釋所反映的那樣,引用存儲在$ items數組中的許多“NodeItems”和“NodeItems”引用了“節點”。 那些是雙向引用的集合。

我的問題是如何有效地從其集合中刪除一些“NodeItem”文檔(基於可用ID數組),以便刪除的NodeItem文檔也從'Node'中的$ items數組引用中刪除(我認為級聯刪除)是我要求的?)。

我寫了一個函數,其代碼如下:

   $qb = $this->dm->createQueryBuilder('SomeBundleBundle:NodeItem');
    /*
     * deletes from NodeItem collection
     */
    foreach($NodeItemsArray as $itemId){
        $qb->remove()->field('id')->equals($itemId)->getQuery()->execute();
    }

但是上面的函數只刪除NodeItem集合中的文檔,但是'Node'的$ items數組中的相關項不會被刪除。 此外,注釋中的{cascade:persist}似乎沒有幫助。 代碼在Symfony 2框架中實現

一些幫助表示贊賞!

實現這一目標的唯一方法是使用onRemove事件上的偵聽器。

但是@jmikola已經提到過,你必須使用$ dm-> remove()方法,而不是QueryBuilder(因為它還不支持事件)。


所以, 要刪除Item do:

//Get the NodeItem you want in the items array and delete it:
$items = $node->getItems();
$dm->remove($items->get(2)); //Remove the third item as an example

注冊活動

class CascadeNodeDeleterListener {
        public function preRemove(LifecycleEventArgs $eventArgs) {

        $odm = $eventArgs->getDocumentManager(); /* @var $odm DocumentManager */
        $object = $eventArgs->getDocument();
        if($object instanceOf NodeItem) {
                $node = $object->getNode();
                $items = $node->getItems();
                $items->removeElement($object);
                $class = $dm->getClassMetadata(get_class($node));
                $dm->getUnitOfWork()->recomputeSingleDocumentChangeSet($class, $node);
            }

        }
}

services.yml

 <service id="listener" class="CascadeNodeDeleterListener">
      <tag name="doctrine.common.event_listener" event="onRemove" />
 </service>

請參閱更多信息,了解Doctrine ODM Events

ODM中的級聯行為僅受UnitOfWork操作的尊重。 MongoDB本身不支持級聯和觸發器(無論如何)。 在您的情況下,查詢構建器將構造並執行如下查詢:

db.node_items.remove({"_id": ObjectId("...")})

UnitOfWork根本不涉及(沒有分階段操作或刷新)並且沒有觸發級聯。

另一方面,假設您有一個托管的$nodeItem對象。 將它傳遞給DocumentManager::remove()將調用UnitOfWork並導致任何使用cascade=REMOVEcascade=ALL映射的引用文檔也將被刪除。 當然,您必須調用flush()來執行MongoDB中的操作。

根據您當前的代碼,將級聯的唯一操作是DocumentManager::persist() 在實踐中,我假設您創建一個Node,構造並向其添加一些NodeItem,並持久化Node(允許其項自動保留)。

如果NodeItems只屬於一個節點,你可能想要避免cascade=REMOVE並且在刪除$nodeItem本身之后只需要執行$nodeItem->getNode()->getItems()->removeElement($nodeItem) flush()

另外,我注意到你正在將你的集合字段初始化為一個數組。 稍后,ODM將把這個字段保存為Doctrine\\ODM\\MongoDB\\PersistentCollection實例,這可能導致歧義。 作為最佳實踐,您應該在構造函數中初始化諸如Doctrine\\Common\\Collections\\ArrayCollection類的字段。 這樣,您始終可以期望它們是Collection實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM