doctrine / mongodb-odm

The Official PHP MongoDB ORM/ODM
https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/
MIT License
1.09k stars 502 forks source link

Add strategy to collection fields #1286

Closed tux-rampage closed 2 years ago

tux-rampage commented 8 years ago

The collection type should allow strategies for atomic operation like addToSet or pull. For example the user wants to keep a string list in his object, and its changes to this list should be save in multiple requests/threads.

Right now this is not possible, the last flush() wins and discards modifications in another request.

Example (Request 1):

// Expect $object was already persisted and is tracked by the document manager
// assume $object->tags already contains values like [ 'existingstring' ] 
$object->tags[] = 'newstring a';
$dm->flush($object);

Example (Request 2):

// Expect $object is the same (_id) as in Request 1. It was loaded before the
// changes in Request 1 were flushed. Now this becomes a problem:
$object->tags[] = 'newstring b';
$dm->flush($object);

The result for the tags field will now be either [ existing values, 'newstring a' ] or [ existing values, 'newstring b' ] (depending on which flush is the later one), but never [ existing values, 'newstring a', 'newstring b' ]. So one modification is lost.

malarzm commented 8 years ago

I'm not sure if we want to go down this way as that'll be another thing happening in separate queries which we tried to avoid by introducing atomicSet and atomicSetArray strategies for collections...

Anyway @tux-rampage for now you could try

  1. employing versioning so ODM will throw an exception on write attempt if another request updated document in the meantime
  2. if tag is the only thing being changed and the clash is expected to happen often it should be easy to update document using query builder and running $push manually
tux-rampage commented 8 years ago

Thanks for your feedback. I just saw I made a mistake. This is related to collection fields, not hash fields. Doing an atomic operation on a hash is quite simple, using $set with the dot notation (Also not supported, yet).

As for the write attempt:

I'd make the default strategy to REPLACE, to behave like it does right now, and the addToSet, push, etc. strategies as opt in. I guess the one who does need the update safety will happily accept the additional write attempt for the benefit. I could image MongoBatchUpdate will become handy here.

To your suggestion using the query builder: This might work, but the real world is more complex and additionally to updating the document, I have to write additional persistence code. Then why should I use Doctrine, if I have to write boilerplate code to track changes to a collection and do a simple $push that could be managed by the mapper?

alcaeus commented 6 years ago

Scheduling for 2.x - collections should get the same treatment that referenceMany and embedMany will get due to new array update operators in MongoDB 3.6.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in a week if no further activity occurs. Thank you for your contributions.