Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query document based on a reference to a cached object

I have two types of objects User and Company whose data is stored in MongoDB collections user and company. User contains a reference to Company. I can query for user using the following code in the UserRepository:

$this
  ->createQueryBuilder()
  ->field('employer')->references($company);

Company however is a heavy used object which is cached using Redis. When no cache is present, everything works fine. But when the company instance was fetched from the cache. The Doctrine unit of work does not know about the instance. Executing the code above will therefore result in the following error:

Cannot create a DBRef for class App\Document\Company without an identifier. Have you forgotten to persist/merge the document first?

I have found out that I can use a hack to register the company with the unit of work after fetching it from Redis:

$company = $this->fetchFromCache($params);
$documentManager->getUnitOfWork()->registerManaged($company, $company->getId(), []);

However, this seems ugly. Is there a way that I can query for the users without having to let Doctrine know about the Company object, or changing my datamodel?

like image 632
Xatoo Avatar asked Nov 06 '22 15:11

Xatoo


1 Answers

Unfortunately if you want to use ODM for querying you need to somehow let the ODM know about your object. While your registerManaged will work as it registers the document in the UnitOfWork it has a downside that any relations you might have there will be broken and/or Doctrine will assume they're new during persist/flush. You could try something along this:

$company = $this->fetchFromCache($params);
if ($dm->getUnitOfWork()->containsId($company->getId(), Company::class)) {
    return $dm->find(Company::class, $company->getId());
}
return $dm->merge($company);

As noted before, merge will recursively merge your documents and its embedded documents/relationships are and mark them as managed by ODM, just like they'd be just fetched. Please note that merging will conform to your cascading settings for references. More info about merging can be found in the docs. Also be aware that merging documents can affect already fetched documents and update their fields with what is being merged.

Merge operation will be only executed once as just before we're checking whether ODM already manages a company identified by an id fetched from the cache. If it does, we're calling $dm->find() which will not hit database as first it'll look up in-memory map of objects and return you the instance that is already managed. This way you'll always get a document managed by the ODM avoiding query to the database.

like image 169
malarzm Avatar answered Nov 14 '22 21:11

malarzm