Doctrine Mongo ODM UniqueIndex is replicated


Doctrine Mongo ODM UniqueIndex is replicated

我正在玩我从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;
    ....

你可以看到文档在两个键(Name和Lang)上有一个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中找到相同对名称/lang的数据时,它们应该是唯一的,但却被复制了:

> 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") }

我的目标是使/lang对名称对于持久化来说是唯一的。

最后我有两个问题:

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

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

但是现在不是更新我的条目,而是为重复条目抛出错误。我应该使用自定义id吗?

尝试像这样使用ensureIndexes:

$dm = $this->get('doctrine_mongodb')->getManager();
$dm->getSchemaManager()->ensureIndexes();

索引只确保文档不被复制。

如果你想做一个相当于"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注释)。

所以如果额外的查询不是问题,使用第一个方法