![](/img/trans.png)
[英]How to find by referenced document in Doctrine ODM with MongoDB?
[英]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=REMOVE
或cascade=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.