如何使用mongodb从doctrine ODM中引用的文档数组中删除文档
我有一个php对象映射到一个具有结构的mongodb文档(称为节点)如何使用mongodb从doctrine ODM中引用的文档数组中删除文档,mongodb,symfony,doctrine,doctrine-orm,Mongodb,Symfony,Doctrine,Doctrine Orm,我有一个php对象映射到一个具有结构的mongodb文档(称为节点) use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; class Node{ /** * @MongoDB\Id */ protected $id; /** * @MongoDB\String */ protected $domain; /** * @MongoDB\Referenc
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
}
正如上面的注释所反映的,“Node”引用了存储在$items数组中的许多“NodeItems”,而“NodeItems”引用了一个“Node”。因此,这些是双向引用集合
我的问题是如何有效地从其集合中删除一些“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}似乎也没有帮助。该代码在symfony2框架中实现
谢谢你的帮助 ODM中的级联行为只受UnitOfWork操作的尊重。MongoDB本机不支持级联和触发器(但无论如何)。在您的情况下,查询生成器将构造并执行如下查询:
db.node_items.remove({"_id": ObjectId("...")})
根本不涉及UnitOfWork(不存在分阶段操作或冲洗),也不触发级联
另一方面,假设您有一个托管的$nodeItem
对象。将其传递给DocumentManager::remove()
将调用UnitOfWork,并导致使用cascade=remove
或cascade=ALL
映射的任何引用文档也被删除。当然,您必须调用flush()
来执行MongoDB中的操作
根据当前代码,将级联的唯一操作是DocumentManager::persist()
。在实践中,我假设您将创建一个节点,构造并向其中添加一些NodeItems,然后持久化该节点(允许自动持久化其项)
如果NodeItems只属于一个节点,您可能希望避免cascade=REMOVE
,只需在删除$nodeItem
本身之后,但在刷新()之前,执行$nodeItem->getNode()->getItems()->removeElement($nodeItem)
另外,我注意到您正在将集合字段初始化为数组。稍后,ODM将把这个字段作为Doctrine\ODM\MongoDB\PersistentCollection
实例,这可能会导致歧义。作为最佳实践,您应该在构造函数中初始化Doctrine\Common\Collections\ArrayCollection
等字段。这样,您总是可以期望它们是集合实例。实现这一点的唯一方法是使用onRemove事件的侦听器
但是@jmikola提到,您必须使用$dm->remove()方法,而不是QueryBuilder(因为它还不支持事件)
因此,要删除该项,请执行以下操作:
//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>
查看更多信息