Reputation: 1133
I'm playing with the UniqueIndex that I picked from the doc of Doctrine ODM and it seems I have a misanderstood of what it aims to do.
Indeed I have a Keyword Document mapped by 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;
....
As you can see the Document has an uniqueIndex on 2 keys (Name and Lang)
I have a all simple script which persist this Document
....
....
$keyword=new \App\Document\Keyword();
$keyword->setCreateDate(new \DateTime());
$keyword->setLang("fr");
$keyword->setLastParseDate(new \DateTime());
$keyword->setName("test");
$dm->persist($keyword);
$dm->flush();
Now when i find from mongo shell, my data with the same pair Name/lang are replicated when they should be unique :
> 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") }
My goal is to make the pair name/lang unique for persistence.
So I finally have two questions :
custom strategy
that concatenates Name and Lang as an unique id ? Is it a common usage ?EDIT :
Thanks to @gview advices I found that i didnt ensureIndexes. I fixed thanks to this link : http://www.testically.org/2011/08/25/using-a-unique-index-in-mongodb-with-doctrine-odm-and-symfony2/
But now instead of update my entry, it throws an error for duplicate entry. Should i use custom id as i said above ?
Upvotes: 1
Views: 939
Reputation: 1349
Try to use ensureIndexes like this:
$dm = $this->get('doctrine_mongodb')->getManager();
$dm->getSchemaManager()->ensureIndexes();
Upvotes: 1
Reputation: 2114
The index ensure only that the Documents don't get duplicated.
If you want to do the equivalent of a "REPLACE INTO", you should either:
Get the document if present, then set the values:
$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");
This will lead to 2 queries.
Or:
Do an upsert:
$dm->createQueryBuilder('Keyword')
->setNewObj(array(
'lang' => 'fr',
'name' => 'test',
// ... other fields
))
->field('lang')->equals('fr')
->field('name')->equals('test')
->getQuery()
->execute();
This will update the doc if present, otherwise it will create a new Document.
However, the new document is created from the raw array, actually bypassing all the Doctrine events (like the @Timestampeble annotation).
So if the extra query isn't a problem, use the first method.
Upvotes: 0