How can Doctrine ODM be used to create a one-to-one bi-directional reference that lazy loads while using a field other than the primary key for the reference?
I have two collections in MongoDB with documents, Article and ArticleMetaData. For every Article document, there is an ArticleMetaData and vise versa. (A OneToOne Bi-Directional relationship.) For legacy reasons, the two document types need to be in separate collections. Both collections are updated by external systems that have no knowledge about the Mongo IDs. They do however contain a shared field "groupcode" which can be used to match the right article to its meta data.
I try to configure Doctrine in such a way that I can get the meta data for an article object and an article from its meta data object but I want to keep them lazy loaded. (There is no need to query for the other end when I don't need it.)
The mappings look as follows:
Foo\BarBundle\Document\Article:
repositoryClass: Foo\BarBundle\Repository\ArticleRepository
changeTrackingPolicy: DEFERRED_EXPLICIT
collection: article
type: document
fields:
id:
id: true
groupcode:
type: int
index: true
unique:
order: asc
...
referenceOne:
metaData:
targetDocument: Foo\BarBundle\Document\ArticleMetaData
mappedBy: groupcode
repositoryMethod: findOneByArticle
Foo\BarBundle\Document\ArticleMetaData:
repositoryClass: Foo\BarBundle\Repository\ArticleMetaDataRepository
changeTrackingPolicy: DEFERRED_EXPLICIT
collection: article_meta
fields:
id:
id: true
groupcode:
type: int
index: true
unique:
order: asc
...
referenceOne:
article:
targetDocument: Foo\BarBundle\Document\Article
mappedBy: groupcode
repositoryMethod: findOneByMetaData
And the repository methods mentioned above:
// In the ArticleRepository
public function findOneByMetaData(ArticleMetaData $metadata)
{
$article = $this
->createQueryBuilder()
->field('groupcode')->equals($metadata->getGroupcode())
->getQuery()
->getSingleResult();
$article->setMetaData($metadata);
return $article;
}
// In the ArticleMetaDataRepository
public function findOneByArticle(Article $article)
{
$metaData = $this
->createQueryBuilder()
->field('groupcode')->equals($article->getGroupcode())
->getQuery()
->getSingleResult();
$metaData->setArticle($article);
return $metaData;
}
It all seems to work quite well. I can query an Article or ArticleMetaData and get the other side, only the problem is: it does not seem to lazy load. When I query for an Article:
$article = $documentManager
->getRepository('FooBarBundle:Article')
->findOneBy(['groupcode' => 123]);
A lot of queries are executed:
doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article"}
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]}
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":null,"query":{"groupcode":123},"fields":[]}
doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article_meta"}
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]}
doctrine.INFO: MongoDB query: {"find":true,"query":{"groupcode":123},"fields":[],"db":"development","collection":"article"}
doctrine.INFO: MongoDB query: {"limit":true,"limitNum":1,"query":{"groupcode":123},"fields":[]}
What am I doing wrong? Is there I way I can accomplish a lazy loading one-to-one bi-directional reference having the above constraints?
Edit:
After reading Rob Holmes' answer I removed a test in the repository methods that could have caused the issue. Unfortunately the problem still remains and there are still 3 queries being executed where one (or two at most) suffice.