1

我正在玩我从 Doctrine ODM 的文档中挑选的 UniqueIndex,似乎我误解了它的目的。

事实上,我有一个由 Doctrine ODM 映射的关键字文档:

Namespace App\Document;

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

/**
 * @ODM\Document
 * @ODM\UniqueIndex(keys={"name"="asc", "lang"="asc"})
 */
class Keyword {

    /** @ODM\Id(strategy="AUTO") */
    protected $id;

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

    /** @ODM\String */
    protected $lang;

    ....

如您所见,文档在 2 个键(名称和语言)上有一个 uniqueIndex

我有一个简单的脚本来保存这个文档

    ....
    ....
    $keyword=new \App\Document\Keyword();
    $keyword->setCreateDate(new \DateTime());
    $keyword->setLang("fr");
    $keyword->setLastParseDate(new \DateTime());
    $keyword->setName("test");

    $dm->persist($keyword);

    $dm->flush();

现在,当我从 mongo shell 中找到时,我的具有相同名称/语言对的数据在它们应该是唯一的时候被复制:

> db.Keyword.find()
{ "_id" : ObjectId("5171c72c6155795e47000000"), "name" : "test", "lang" : "fr", "createDate" : ISODate("2013-04-19T22:37:32Z"), "lastParseDate" : ISODate("2013-04-19T22:37:32Z") }
{ "_id" : ObjectId("5171c7366155796147000000"), "name" : "test", "lang" : "fr", "createDate" : ISODate("2013-04-19T22:37:42Z"), "lastParseDate" : ISODate("2013-04-19T22:37:42Z") }
{ "_id" : ObjectId("5171c7406155796447000000"), "name" : "test", "lang" : "fo", "createDate" : ISODate("2013-04-19T22:37:52Z"), "lastParseDate" : ISODate("2013-04-19T22:37:52Z") }
{ "_id" : ObjectId("5171c7fd615579a747000000"), "name" : "test", "lang" : "fo", "createDate" : ISODate("2013-04-19T22:41:01Z"), "lastParseDate" : ISODate("2013-04-19T22:41:01Z") }
{ "_id" : ObjectId("5171c7fe615579aa47000000"), "name" : "test", "lang" : "fo", "createDate" : ISODate("2013-04-19T22:41:02Z"), "lastParseDate" : ISODate("2013-04-19T22:41:02Z") }

我的目标是使这对名称/语言对持久性具有唯一性。

所以我最后有两个问题:

  • UniqueIndex 是做什么用的?(因为它不会阻止复制)
  • 我应该使用custom strategy连接 Name 和 Lang 作为唯一 id 吗?这是一种常见的用法吗?

编辑 :

感谢@gview 的建议,我发现我没有确保索引。我通过这个链接修复了:http ://www.testically.org/2011/08/25/using-a-unique-index-in-mongodb-with-doctrine-odm-and-symfony2/

但是现在它没有更新我的条目,而是引发重复条目的错误。我应该像上面所说的那样使用自定义 ID 吗?

4

2 回答 2

1

尝试像这样使用 ensureIndexes:

$dm = $this->get('doctrine_mongodb')->getManager();
$dm->getSchemaManager()->ensureIndexes();
于 2018-12-11T13:05:07.877 回答
0

该索引仅确保文档不会重复。

如果您想做相当于“REPLACE INTO”的操作,您应该:


获取文档(如果存在),然后设置值:

$keyword= $dm->findBy(array("name"=> $name, "lang"=> $lang));
if(!$keyword) {
    $keyword= new Keyword();
    $dm->persist($keyword);
}
$keyword->setCreateDate(new \DateTime());
$keyword->setLang("fr");
$keyword->setLastParseDate(new \DateTime());
$keyword->setName("test");

这将导致 2 个查询。


或者:

做一个 upsert:

$dm->createQueryBuilder('Keyword')
   ->setNewObj(array(
       'lang' => 'fr',
       'name' => 'test',
       // ... other fields
   ))
   ->field('lang')->equals('fr')
   ->field('name')->equals('test')
   ->getQuery()
   ->execute();

这将更新文档(如果存在),否则将创建一个新文档。

但是,新文档是从原始数组创建的,实际上绕过了所有 Doctrine 事件(如 @Timestampeble 注释)。

因此,如果额外的查询不是问题,请使用第一种方法。

于 2013-04-29T10:03:05.510 回答