Fos elastica:更新嵌套对象的ES数据

时间:2015-03-13 11:13:38

标签: symfony object nested foselasticabundle

我使用fos:elastica处理Symfony2项目。用户可以喜欢和关注他们喜欢的地方。默认情况下,当用户喜欢某个地方时,我们会自动添加"以下"行动。

首先,我将这两个动作保存在数据库中(doctrine2)。我的数据正确保存在db中。

当我使用索引" user_action"进行ES查询时我得到了与某个地方相关的所有行动(以前喜欢和以下)。

但是当我对索引做同样的事情"放置"我只得到第一个动作(如)。

似乎ES无法在建议对象中更新userAction。

另一方面,如果我删除了一个"跟随"动作(在类似之后自动添加)并且我进行第二次调用(通过api)我的动作保存在db中并且还在位置对象中更新。

希望有人能理解我所说的和我尝试做的事^^

映射

位置

place:
     mappings:
      id:
       type: integer
      userAction:
       type: nested
       properties:
         userId:
           type: integer
         userActionTypeId:
           type: integer
         userActionType:
           type: nested
           properties:
             name:
               type: string

用户操作

user_action:
    mappings:
          userId:
            type: integer
          placeId: ~
          place:
            type: nested
            properties:
              id:
                type: integer
          userActionType:
            type: nested
            properties:
              name: ~

监听

服务

`fos_elastica.listener.place.user_action`:
   class: API\Rest\v1\PlaceBundle\EventListener\ElasticaUserActionListener
   arguments:
       - @fos_elastica.object_persister.search.user_action
       - ['postPersist', 'postRemove']
       - @fos_elastica.indexable
   calls:
       - [ setContainer, ['@service_container', @fos_elastica.object_persister.search.place ] ]
   tags:
       - { name: 'doctrine.event_subscriber' }

<?php

namespace API\Rest\v1\PlaceBundle\EventListener;

use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as BaseListener;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use Symfony\Component\DependencyInjection\ContainerInterface;
use API\Rest\v1\UserActionBundle\Entity\UserAction;

class ElasticaUserActionListener extends BaseListener
{
    private $container;
    private $objectPersisterSuggestion;

    public function setContainer(ContainerInterface $container, ObjectPersister $objectPersisterSuggestion)
    {
        $this->container                 = $container;
        $this->objectPersisterPlace = $objectPersisterPlace;
    }

    public function postPersist(EventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();

        if ($entity instanceof UserAction) {
            $this->scheduledForInsertion[] = $entity;
            $this->objectPersisterPlace->replaceOne($entity->getPlace());
        }
    }

    public function postRemove(EventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();

        if ($entity instanceof UserAction) {
            $this->scheduleForDeletion($entity);
            $this->objectPersisterPlace->replaceOne($entity->getPlace());
        }
    }
}

当前结果

使用嵌套对象userAction获取位置(#320)

query : http://localhost:9200/search/place/_search
"hits" : [
    {
        "_index" : "search",
        "_type" : "place",
        "_id" : "320",
        "_score" : 5.7004805,
        "_source":{
            "userAction":[
                {
                    "userActionType":{
                        "name":"like"
                    },
                    "userActionTypeId":3,
                    "userId":3
                }
            ]
        }
    }
]

获取与ID为#320

的地点相关的用户操作
query : http://localhost:9200/search/user_action/_search
"hits" : [
    {
        "_index" : "search",
        "_type" : "user_action",
        "_id" : "50",
        "_score" : 5.7004805,
        "_source" : {
            "userId" : 4,
            "placeId" : 320,
            "userActionType" : {
                "name" : "following"
                }
            }
    },
    {
        "_index" : "search",
        "_type" : "user_action",
        "_id" : "49",
        "_score" : 5.402646,
        "_source" : {
            "userId" : 4,
            "placeId" : 320,
            "userActionType" : {
                "name" : "like"
            }
        }
    }
]

更新(解决方案)

我终于找到了正确的方法。我太快就冲了数据。

我替换了这个错误的代码

$em = $this->getEntityManager();
$em->persist($like);
$em->flush();  

$em = $this->getEntityManager();
$em->persist($following);
$em->flush();  

通过

$em = $this->getEntityManager();
$em->persist($like);
$em->persist($following);  
$em->flush();

它正在工作!!!!

希望这可以帮助某人。

1 个答案:

答案 0 :(得分:0)

对于我来说,使用FOSElasticaBundle 3.0.x来更新嵌套对象的方法通常如下:

将此添加到app/config/config.yml

services:
    # your other services

    fos_elastica.listener.search.user_action:
        class: "Acme\Bundle\UserActionBundle\EventListener\ElasticaUserActionListener"
        arguments:
            - @fos_elastica.object_persister.search.user_action
            - ['postPersist', 'postInsert', 'postUpdate', 'preRemove']
            - @fos_elastica.indexable
            - { indexName: 'user_action', typeName: 'userAction'}
        calls:
            - [ setContainer, ['@service_container', @fos_elastica.object_persister.search.user_action] ]
        tags:
            - { name: 'doctrine.event_subscriber' }

然后在UserActionBundle\EventListener中创建一个新文件:

# Acme\Bundle\UserActionBundle\EventListener\ElasticaUserActionListener.php
namespace Acme\Bundle\UserActionBundle\EventListener;

use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as BaseListener;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use Symfony\Component\DependencyInjection\ContainerInterface;

class ElasticaUserActionListener extends BaseListener
{
    private $container;
    private $objectPersisterUserAction;

    public function setContainer(ContainerInterface $container, ObjectPersister $objectPersisterUserAction)
    {
        $this->container = $container;
        $this->objectPersisterUserAction = $objectPersisterUserAction;
    }

    public function getClassAccessorArray() {
        return [
            [
                'accessor' => 'getPlace', 
                'class' => new Place(),
            ],
            // add more child objects here, if needed
        ];
    }

    public function postPersist(EventArgs $args)
    {
        $entity = $args->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];
            if ($entity instanceof $class) {
                $this->scheduledForInsertion[] = $entity;
                $this->objectPersisterUserAction->insertOne($entity->$accessorFunction());
                break;
            }
        }
    }

    public function postUpdate(EventArgs $args)
    {
        $entity = $args->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];
            if ($entity instanceof $class) {
                $this->scheduledForUpdate[] = $entity;
                $this->objectPersisterUserAction->replaceOne($entity->$accessorFunction());
                break;
            }
        }
    }

    public function preRemove(EventArgs $eventArgs) {
        $entity = $eventArgs->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];

            if ($entity instanceof $class) {
                $this->scheduleForDeletion($entity);
                $this->objectPersisterUserAction->deleteOne($entity->$accessorFunction());
            }
        }
    }
}

这可以在直接更新嵌套对象时更新ElasticSearch的索引。在您的情况下,因为您实际上在PlaceUserAction之间存在双向关系,您可以扩展Listener类来处理这两个类,或者只是复制并创建ElasticaPlaceListener服务和班级。