我正在玩我从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;
....
如您所见,Document在2个键(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唯一的持久性。
所以我最后有两个问题:
custom strategy
吗?这是一种常见用法吗?编辑:
感谢@gview建议我发现我没有确保索引。我已经修复了这个链接:http://www.testically.org/2011/08/25/using-a-unique-index-in-mongodb-with-doctrine-odm-and-symfony2/
但是现在不是更新我的条目,而是为重复输入引发错误。我应该如上所述使用自定义ID吗?
答案 0 :(得分:1)
尝试使用此类的suresureIndexes:
$dm = $this->get('doctrine_mongodb')->getManager();
$dm->getSchemaManager()->ensureIndexes();
答案 1 :(得分: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注释)。
因此,如果额外查询不是问题,请使用第一种方法。