colinmollenhour / mongodb-php-odm

A simple but powerful set of wrappers for using MongoDb in PHP (also a Kohana 3 module)
BSD 3-Clause "New" or "Revised" License
208 stars 50 forks source link

Mongo server operations emulation - so you don't have to reload your document. #41

Closed panrafal closed 11 years ago

panrafal commented 11 years ago

Most of mongo field functions like inc, push, pull etc. can be emulated, so you don’t have to reload the document to see the changed values. Actual document processing is of course still done on the server.

You can enable it by default by setting $_emulate to true, or by using set_emulation(true). Additionaly, every emulated function accepts $emulate parameter.

This pull request is based on phpUnit requests.

colinmollenhour commented 11 years ago

This seems like a lot of additional complexity (confusion) and I'm not so sure it is the direction I want to go.. What do you think @sergeyklay?

panrafal commented 11 years ago

For me it was very inconsistent, that set(), inc() and the rest did not "do" anything before saving. Plus they mark the property as dirty which adds its own headaches. This allows to do many operations on a document without duplicates or multiple save+reads - and only save once at the end. So on one end it adds complexity, and it removes it on the other. Personally I use the lib set in this mode permanently.

sergeyklay commented 11 years ago

Yes, I also thought it a bit confusing. I think the API should be easier. Clearer

colinmollenhour commented 11 years ago

The problem is that by emulating what the server was doing you are making a huge assumption that nothing else has changed the same data in the meantime.. That is the whole point of the atomic operations, otherwise you might as well use the non-atomic operations (e.g. $set:{a: a+1} instead of $inc{a:1}). Perhaps if you provided a sample use case that demonstrates the motivation I would understand it better.

panrafal commented 11 years ago

Sure. 1) Imagine having a loop, where you parse some long input and store results in the mongo document using set with dot notation. With emulation you can check if you've set something already, not to repeat yourself. You can't just set the whole subdocument, because a parallel process might do it's own processing at the same place. Without emulation you have to either keep track of stuff you changed, or reload the document each time. Both of which are not always practical (where input is long, or processing is done in separate function).

2) Imagine using documents as objects in the application. You load one, and put it through a long and somehow complicated process, utilizing many functions. After processing, you can decide whether you want to save the modified document (if there are any changes) or not (if there was an error). Emulation enables you to use operations like push, set, etc. while being able to read the outcomes of those operations without saving.

3) It's simply more natural to assume, that after using push() the changed value will be there when you read it. If you need to know the outcome of an atomic operation - you reload the document, or don't use emulation. But more often then not, you just process the document, store it and forget it.

I think the API is pretty simple - there is a per-document switch, which can also be changed per-model by overriding it. Plus every emulated function accepts the switch $emulate, where you can override the behaviour. There is nothing more to it. It can of course be moved to a subclass, but I don't think it would make it clearer.

It's of course a bit more complicated to develop, because you've to follow the changes in mongodb, but that's why I've also made an extensive test suite, which compares the operations on both ends.

panrafal commented 11 years ago

And I would forget - it allows to use ArrayAccess getters/setters with dot notation #42 . This allows to use documents in functions that even don't know that mongo exists.

colinmollenhour commented 11 years ago

Thanks for the contributions @panrafal and @sergeyklay!

sergeyklay commented 11 years ago

welcome :)

panrafal commented 11 years ago

Thanks for discussion and merging :)