Mongodb-odm: How to best catch changes to a cleared PersistentCollection ?

Created on 6 Feb 2017  路  2Comments  路  Source: doctrine/mongodb-odm

Hello everybody,

I am currently working on a very abstractly written Subscriber that should catch and process all sort of changes on any given Document.

While trying that I encountered an edge that I don't know how to handle:

1) My document keeps an embedMany collection of subdocuments.
2) I call $document->collection->clear()
3) I then flush

How can I catch the changes to the collection property ?

My subscriber currently reacts to doctrine's onFlush event. So far I have tried to following (all without success) :

  • Iterating over ScheduledDocumentInsertions
  • Iterating over ScheduledDocumentUpserts
  • Iterating over ScheduledDocumentUpdates
  • Iterating over the complete IdentityMap() and calling $unitOfWork->getScheduledCollections($document) for each document and try to find the change there

I seem to be unable to find the document or its collection in any of those cases. I strongly feel though, that doctrine should keep a reference to the collection if it plans to clear it of all content during the actual database commit.

I would gladly appreciate any help or hints towards a workable solution.

Most helpful comment

I strongly feel though, that doctrine should keep a reference to the collection if it plans to clear it of all content during the actual database commit

The collection may not even have been initialized - that's the main reason why you're seeing the behavior described. It would be ridiculous to load a collection just to clear it, which is why we're not removing elements one by one but rather scheduling it as a collection removal.

When calling clear on an owning-side persistent collection, you can use the getScheduledCollectionDeletions method in UnitOfWork to get all persistent collections that have been cleared.

However, if you need to know the elements that were present in the collection before clearing it, you're out of luck. In that case, iterate over the collection and remove all elements one by one. This will not trigger a collection deletion but keeps the original snapshot so you can get a diff of documents. Let me just add that this may be a very dangerous operation depending on how many documents you have in your collection - loading potentially thousands of documents just for the sake of removing them will ruin your performance. Depending on your use-case, there may be other, more efficient ways of achieving your goal.

Note: I've had a similar issue, which spawned #1034. I've outlined our solution in this comment.

All 2 comments

I strongly feel though, that doctrine should keep a reference to the collection if it plans to clear it of all content during the actual database commit

The collection may not even have been initialized - that's the main reason why you're seeing the behavior described. It would be ridiculous to load a collection just to clear it, which is why we're not removing elements one by one but rather scheduling it as a collection removal.

When calling clear on an owning-side persistent collection, you can use the getScheduledCollectionDeletions method in UnitOfWork to get all persistent collections that have been cleared.

However, if you need to know the elements that were present in the collection before clearing it, you're out of luck. In that case, iterate over the collection and remove all elements one by one. This will not trigger a collection deletion but keeps the original snapshot so you can get a diff of documents. Let me just add that this may be a very dangerous operation depending on how many documents you have in your collection - loading potentially thousands of documents just for the sake of removing them will ruin your performance. Depending on your use-case, there may be other, more efficient ways of achieving your goal.

Note: I've had a similar issue, which spawned #1034. I've outlined our solution in this comment.

Thanks for the fast and comprehensive reply.

Initialising the collection does indeed seem to fix the problem. I agree though that it is not a feasible approach.

I also appreciate the hint towards getScheduledCollectionDeletions. However, it won't suit my needs, as I also need to know which elements have been removed from the collection. And as you pointed out, I cannot access that information at that time.

I checked out the referenced issue #1034 which seems pretty similar to my problem. So it seems like a will have to use a custom collection class. Something I wanted to avoid as it hinders the universal usability of my subscriber. But apparently this is the doctrine way to go about things.

Again thank you.

I will close this issue as I feel that my question has been sufficiently answered.

Was this page helpful?
0 / 5 - 0 ratings