TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
Release: Mango; a ORM like library for MongoDB
  • There's this new high performance, document-based and schema-less database called MongoDB (http://www.mongodb.org).

    I wrote a library - Mango - that offers some relational features on top of MongoDB, so you can enjoy the speed and flexibility of MongoDB, and still work with objects like you're used to with ORM.

    Of course - if you need transactions, or something else complicated - use a RDBMS, but in other cases, MongoDB has some interesting features, and with this library, development will become a bit easier.

    Check it @ http://github.com/wouterrr.

    Oh it also includes a very simple queue system (MangoQueue::set() and MangoQueue::get())
  • Awesome, thanks!
  • Hmm, interesting. Always looking for alternative DB systems for some problem cases in my site :) Do you have any use case examples where you're using Mongo? Or in what situations you might use Mongo over the traditional MySQL/PostgreSQL etc?

  • A key goal of MongoDB is to bridge the gap between key/value stores (which are fast and highly scalable) and traditional RDBMS systems (which are deep in functionality). (Source: http://www.mongodb.org)

    :-)

    They're trying to replace the Memcached/Mysql/ORM stack. More here: http://www.mongodb.org/display/DOCS/Philosophy & http://www.mongodb.org/display/DOCS/Use+Cases.

    I'm not too experienced yet with Mongo - discovered it about 2 weeks ago :-), but for example, if you have been working on denormalizing your data, you could take a look at MongoDB. One of many advantages is that mongo allows you to denormalize your data (for example store the blogpost object and all comments to the blogpost in one document (so very fast retrieval from DB) without losing the power to query the data (you could run a query to select all comments from a single author).

    Or if you're working with a large associative array in your code, and before saving you have to replace that array by something that can be stored in MySQL. I'm sure there are many more examples - I'm still learning :-) - but saving large associative arrays, and objects in objects, without losing the possibility to query, where great for my app!
  • Will have to do some more research on Mongo then :) Mainly I'm looking for something to handle large forums and full text searches, though

  • I never tried it, but there's a system called Sphinx, that offers high performance text searches. If you haven't heard of it, check it at http://sphinxsearch.com/
  • As I'm getting more and more understanding of MongoDB and the document-based way of thinking, I made many improvements to my Mango library.

    Now - besides the RDBMS like features (mostly all relationships that ORM also supports), I added some more fancy features:

    To push a value into an array, call $object->set[] = 'some value'; - even if $object->set has not been set yet.

    To increase a counter, call $object->counter->increment() - even if $object->counter has not been set yet

    I also added support for a multidimensional array of counters. You could do: $object->site = array(
    'views' => 0,
    'clicks' => 0,
    'pages' => array(
    '12' => array(
    'views' => 0,
    'clicks' => 0
    )
    )
    );


    Save it,

    increment/decrement when needed:
    $object->site['pages']['12']['views']->increment(5); (this corresponds to a $inc => { site.pages.12.views : 5 } update)

    and show it when needed:
    echo 'this site has' . $object->site['total'] . ' views';

    Nice :-)
  • Just an FYI, you used mango and not mongo. :)
  • I know, don't you like my very original name?! :-)
  • I realized after I posted that it was intentional, sorry. :)
  • I ported my libraries to KO3. I figured that anyone trying MangoDB (which is in release 0.97) probably also uses KO3 :-). The KO3 version will be the one that gets all the updates.

    I would like it if one of the admins could open a Mango project for me on projects.kohanaphp.org so I can list it over there as well.

    Anyway, see http://github.com/Wouterrr/MangoDB and http://github.com/Wouterrr/MangoDemo
  • @Wouter

    Great work - just a quick question:

    Does your task queue ONLY support MangoDb? If we wanted to use MySQL - would we have to rework the task Queue module built for KO2?
  • Do you have any examples? Where do I put the files? I am new to Kohana.

    Thanks,
    Bill
  • If you are new to Kohana, you will have to spend some time to get to know Kohana. It is not a difficult framework, but depending on how much experience you have with (H)MVC frameworks, PHP programming etc, it will take some time. This would be your step one before you should even start with my MongoDB libraries.

    I would recommend it though, because it's an awesome framework :-). And my libraries for MongoDB are the most advanced out there for PHP. I haven't found another that offers the same level of functionality and features.

    Once you got to know Kohana a bit better, only then you should install the MangoDB module and the MangoDemo module. The latter includes many code examples of how to use MangoDB in your app (everything at http://github.com/wouterrr).

    It's gonna take some time to get to know Kohana, and then some additional time to get your head around MongoDB (it's a different way of thinking about data), but once you've passed all that, it's pretty awesome (I think :-)).
  • @Wouter

    I am testing out your Mango modules (thanks for the hard work), and I will like to know if your ACL and A2 modules also work with Mango.

    Thanks in advance.

    Nano.
  • Yes they do. All you have to do is some commenting/uncommenting in classes/A1.php (Mango::factory and $user->update()) and replace user->id by user->_id

    Of course you'll need a Mango based user model instead of the ORM based on.
  • @Wouter

    I have been playing with your demo and I really like the flexibility you get from Mongo and the nice features you have added to Mango (relationships, cascade deleting, etc...), just wondering: do I need to set all the columns in advance in my models? All the examples I have seen have the different columns already defined in the models, but somewhere in the MongoDB page I saw that Mongo is quite flexible for adding new columns on the fly. Any help will be appreciated.

    Thanks,

    Nano.
  • Mango is an ORM layer on top of the MongoDB PHP driver. To function properly, you have to specify the fields in your models, so Mango knows when a field is a counter, a string, an embedded object or an array.

    You never have to specify fields in MongoDB (although you might want to index certain fields). When using Mango, to add/remove a field, modifying the model definition is enough. No database migrations required :-).

    Also, do realise that there are many use cases for MongoDB where a ORM layer (like Mango) is not necessary.

    Try working with MongoDB from the shell and/or directly with the PHP driver to get a better grip of collections, documents and fields (instead of tables, rows and columns :-)).
  • Is there any reason why the save method of Mongo is not implemented in Mango? I see that there are update, insert, delete, but I don't see the save method.

    Thanks,

    Nano.
  • @nanodocumet: Mango::factory()->create()
  • @rafi,

    but create does an insert [1] internally; save [2] in the other hand will try to update the object if in the collection, otherwise will do the insert.

    [1] http://us2.php.net/manual/en/mongocollection.insert.php
    [2] http://us2.php.net/manual/en/mongocollection.save.php
  • I took the Sprig approach.

    You could add your own save method:

    public function save()
    {
    return $this->loaded()
    ? $this->update()
    : $this->create();
    }


    And again, Mango is an ORM layer for MongoDB. It's about adding ORM (-like) features, not about wrapping Mongo calls in different function names (that's what MangoDB.php does).

    Do not confuse the PHP driver methods with Mango methods!
  • Thanks Wouter, I've seen lately that ActiveRecord-like modules (eg. new ORM, Sprig) have the 2 methods insert/update instead of a single save one.

    By any chance have you migrated your A1 module to extend from Mango instead of ORM?

    Nano.
  • To make the A1 class Mango compatible:

    Posted By: Wouter

    Yes they do. All you have to do is some commenting/uncommenting in classes/A1.php (Mango::factory and $user->update()) and replace user->id by user->_id



    I don't have a generic Mango based user model, but even if I had one, you should really try to create one yourself. Good exercise :-)
  • I think it will take a little bit more than just changing that info, but I will definitely give it a try, I was hoping to save some time :). After long time looking for my best options I have decided to use MangoDB instead of MySql and your modules are very helpful.

    Just out of curiosity, have you used Mango in any real-life web project?

    Thanks,

    Nano.
  • Posted By: nanodocumet

    I think it will take a little bit more than just changing that info



    It won't. I'm using A1 with Mango/MongoDB.

    have you used Mango in any real-life web project?



    Not yet, but these guys have: http://www.mongodb.org/display/DOCS/Production+Deployments
  • @nano, I'm using Mango/MongoDB in my current project, it's awesome :) There's some big names using Mongo as you can see from Wouter's link.

    As far as the A1 with Mango, I took a look in Wouter's repository, and it looks very simple to implement. Just remove the comments :) I didn't get to the login/authentication yet, but I don't see any problems.
  • Yeah... I have managed to have A1 Mango-compliant, and it was really like Wouter said. I added a new property in the A1 configuration file to define when driver to use: ORM or Mango and then inside the A1 I create the objects according to chosen driver. Wouter, if you want to include that in your A1 module please let me know.

    The part that I am working right now is the user model which should be extend from Mango and not ORM (this is actually what I was referring to for the more changes). rafi, if you happen to do the login/authentication logic (model) anytime soon please let me know.

    @rafi, Are you using Mango/MongoDB as your primary database or for statistics and logs?

    Thanks,

    Nano.
  • @nano: I'm using Mongo as my primary database
  • After some tests that I have done, I have discovered the following.

    Case 1) Updating string values in array only work with exact number of characters being updated
    Let's say we have originally a model like this:

    <?php
    class Model_Test extends Mango {

    protected $_fields = array(
    'some_array' => array('type'=>'array', 'type_hint'=>'array'),
    );

    protected $_db = 'demo'; //don't use default db config
    }


    Doing the following code works fine:
    $test = Mango::factory('test');
    $test->some_array[] = array('key1' => '1500', 'key2' => '2500'); // Notice that values are set as strings
    $test->create();


    And it shows on the shell as well:
    > db.tests.find()
    { "_id" : ObjectId("4b37b6da20ac5dbcfe000000"), "some_array" : [ { "key1" : "1500", "key2" : "2500" } ] }


    Now if I want to update the values of the array, it only works IF AND ONLY IF the length of the new string is the same for all the updated values.

    This one works:
    $test = Mango::factory('test', array('_id' => '4b37b6da20ac5dbcfe000000'))->load();
    $test->some_array[0] = array('key1' => 'test', 'key2' => 'test'); // Both need to be the same size to be updated
    $test->update();


    But this one doesn't work:
    $test = Mango::factory('test', array('_id' => '4b37b6da20ac5dbcfe000000'))->load();
    $test->some_array[0] = array('key1' => 'test1', 'key2' => '123');
    $test->update();


    Can the values grow or decrease in size for arrays? Or this is a limitation of MongoDB itself?

    Case 2) Adding new fields to an existing model don't get updated for previous created objects, only for new created objects
    And now, let's add a new field to the model above:
    <?php
    class Model_Test extends Mango {

    protected $_fields = array(
    'some_array' => array('type'=>'array', 'type_hint'=>'array'),
    'name' => array('type'=>'string')
    );

    protected $_db = 'demo'; //don't use default db config
    }


    And if we want to set a value of the new field to an existing object, the value won't be updated.
    This one doesn't work:
    $test = Mango::factory('test', array('_id' => '4b37b6da20ac5dbcfe000000'))->load();
    $test->name = 'test';
    $test->update();


    But if we create a new one, it will create it adequately, even if all the other fields are not there.
    $test = Mango::factory('test');
    $test->name = 'test'; // Gets created
    $test->create();


    Is there any way to add the value of old records for a new created field?
    [Edit]: After some other tests, this seems to be working fine, old records can have new values added without problems

    Case 3) Array notation or object notation?
    Depending on when the arrays are created, they are represented differently. The following code:
    $test = Mango::factory('test');
    $test->name = 'Test';
    $test->some_array[] = array('key1' => 'AAAEFG', 'key2' => 'TEST');
    $test->create();

    $test1 = Mango::factory('test');
    $test1->name = 'Test1';
    $test1->create();

    $test1->some_array[] = array('key1' => '123', 'key2' => 'TEST1');
    $test1->update();


    Creates 2 objects but they are structured in a different way. Notice the way "some_array" is shown below:
    > db.tests.find()
    { "_id" : ObjectId("4b37c0f520ac5d28f9000000"), "some_array" : [ { "key1" : "AAAEFG", "key2" : "TEST" } ], "name" : "Test" }
    { "_id" : ObjectId("4b37c0f520ac5d28f9010000"), "name" : "Test1", "some_array" : { "0" : { "key1" : "123", "key2" : "TEST1" } } }

    I know that when accessing the values it will be the same. This will work for both, just that looked kind of interesting that is not fully consistent (array vs object notation):
    $test = Mango::factory('test', array('_id' => '4b37c0f520ac5d28f9000000'))->load();
    $test->some_array[0] = array('key1' => 'AAAAAA', 'key2' => 'TEST');
    $test->update();

    $test1 = Mango::factory('test', array('_id' => '4b37c0f520ac5d28f9010000'))->load();
    $test1->some_array[0] = array('key1' => '333', 'key2' => 'TESTY');
    $test1->update();


    For this one it was more of an interesting finding, is that how MongoDB works or it is a Mango implementation related issue?

    Thanks,

    Nano.
  • Great you're using the module! And thanks for including your code. It makes reproducing much easier.

    In fact, all the things your experiencing come down to a single issue. Arrays and sets, so I'll try to explain that one first.

    PHP is kind of unique by not only supporting numerical arrays array('value0','value1'), but also associative arrays array('key' => 'value'). All array related PHP methods run on both types of arrays.

    In other languages, an array is always numerical. Otherwise you're dealing with an object. This also goes for MongoDB. MongoDB uses a JSON like storage mechanism. Documents are stored like this

    {
    _id : ObjectId('1234'),
    some_array: [ 'value0', 'value1'],
    some_object: {
    key : 'value'
    }
    }


    I made the following translation from MongoDB arrays and objects to PHP's numerical arrays and associative arrays:

    MongoDB array = PHP numerical array = Mango_Set
    MongoDB object = PHP associative array = Mango_Array

    In your Model_Test, the some_array field is actually a set! Therefore, the correct specification would be:

    <?php
    class Model_Test extends Mango {

    protected $_fields = array(
    'some_set' => array('type'=>'set', 'type_hint'=>'array'),
    'name' => array('type'=>'string')
    );

    protected $_db = 'demo'; //don't use default db config
    }


    All your troubles come down to the differences between arrays and sets ( = MongoDB objects and MongoDB arrays) and how MongoDB deals with them. So fix that, and try to redo your tests :-).

    Some notes:

    1) Updating sets using dotnotated array indeces doesn't work properly in Mongo. Bug is reported here: http://jira.mongodb.org/browse/SERVER-181
    2) I could not recreate this error. If should work properly once you change your 'array' to 'set'.
    3) Same issue array/set thing. If you specify a field as a Mango_Array, but then add only numerical keys, the MongoDB driver (not Mango, but the driver itself) will assume the document is an array because it only sees numerical keys, and stores it as such.
  • Hi Wouter,

    I will implement what you've said and see how it goes and share my findings.

    I really like MongoDB and Mango :)

    Thanks,

    Nano.
  • @Wouter: Hey. Good explanation.


    1) I'm trying to understand when to use or not use the type_hint. Couldn't quite fully understand from the wiki.
    2) Arrays/Sets:

    -------+------------+----------------------
    Mango | Mongo | PHP
    -------+------------+----------------------
    Set | Array | Numerical array
    Array | Object | Associative array
    -------+------------+----------------------


    Pretty confusing. Did I get it right? :-)

    BTW,
    @nano - make sure you read the 32-bit limitation of MongoDB.
  • @Rafi:

    1) It is pretty complex, but I'll try to explain. Consider this field:

    basic_set => array('type'=>'set');

    This will support basic Mango_Set functions like:

    $model = Mango::factory('test');
    $model->basic_set[] = 'value'; // equivalent of ->push()
    $model->basic_set[1] = 'value1';
    $model->basic_set->push('value2'); // equivalent of ->[]


    For Mango_Arrays it's pretty much the same

    basic_array => array('type'=>'array');

    will support basic Mango_Array functions like:

    $model = Mango::factory('test');
    $model->basic_array['key'] = 'value';


    However, sometimes you want to store complex objects in the Mango_Set/Mango_Array. For example Mango_Counters, other Mango_Arrays/Mango_Sets or even embedded objects. With type_hint, you indicate the type of object that is stored in the Mango_Set/Mango_Array.

    For example, an array of counters:

    array_of_counters => array('type'=>'array', 'type_hint' => 'counter');

    Now this supports:

    $model = Mango::factory('test');
    $model->basic_array['key_name']->increment(1);


    Because of the typehint, the still unexisting value at key 'key_name' will be created as a Mango_Counter, immediately supporting the ->increment method. Without the typehint, the module wouldn't know, what type of object should be stored in the 'key_name' key.

    If you want to work with an array of sets, you could do this:

    array_of_sets => array('type'=>'array', 'type_hint' => 'set');

    This will support things like:

    $model = Mango::factory('test');
    $model->basic_array['key_name']->push('value1');


    I hope it's a little bit clearer. To get some understanding of how Mango communicates with MongoDB, I always use:
    echo Kohana::debug($model->changed( $model->loaded()));

    This will show the update query (with atomic modifiers if possible) that Mango will send to the DB when you call ->create() or ->update()!
  • Dude. That was like the best answer in the world. I just smoked a little and you blew my mind :)
    We could store whole object inside, and also have tons of attributes as sets, inside a single array field, and have those attributes act as sets and in each one store a set with i18n locales for multi super editable multi-translated website without dealing with all the freakin' SQL for medium websites like blogs or stores, so cool man! :^)

    I was thinking if MongoDB is basically JSON, how can I get a JSON string directly from the load() method ?
    I'm using a few javascript picker widgets that I want to feed with json over xmlhttp.

    Thanks a zillion!!!
  • @Rafi:
    echo JSON_encode($model->as_array(false));
  • I want to share the following.

    I have this model

    class Model_Person extends Mango {

    protected $_fields = array(
    'siblings' => array('type'=>'set', 'type_hint'=>'array')
    );

    }


    Creating an entry is fine:
    $person = Mango::factory('person');
    $person->siblings[] = array('name' => 'Mary', 'last_name' => 'Smith');
    $person->create();


    But updating will not work, instead it ALWAYS creates a new object for the siblings set.
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0] = array('name' => 'Jane', 'last_name' => 'Smith');
    $person->update();


    Same here:
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[] = array('name' => 'Mary', 'last_name' => 'Smith');
    $person->create();
    $person->siblings[0] = array('name' => 'Jane', 'last_name' => 'Smith'); //Even if values are EXACT size as original values
    $person->update();


    > db.persons.find()
    { "_id" : ObjectId(MongoId), "some_set" : [
    {
    "name" : "Mary",
    "last_name" : "Smith"
    },
    {
    "name" : "Jane",
    "last_name" : "Smith"
    }
    ] }


    Changing the model to use array instead of set, it will work (it updates the value instead of adding entries to siblings object, but with the condition that values are the exact number of characters):
    class Model_Person extends Mango {

    protected $_fields = array(
    'siblings' => array('type'=>'array', 'type_hint'=>'array')
    );

    }


    This will work:
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0] = array('name' => 'Jane', 'last_name' => 'Smith');
    $person->update();


    This will not work: (not same length for attribute name)
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0] = array('name' => 'Mary Jane', 'last_name' => 'Smith');
    $person->update();


    This doesn't update anything either: (missing 'last_name')
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0] = array('name' => 'Jane');
    $person->update();


    However, if I update the value directly by itself it will work (it works for sets as well)
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0]['name'] = 'Jane';
    $person->update();


    The main limitation with this approach is that values cannot grow or shrink in size, thus, updating ONLY works when the same number of characters are updated.

    Notice that adding new key/value pairs doesn't work either. This will fail (I think this is the case for the bug issue that Wouter mentioned):
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings[0]['middle_name'] = 'Jane';
    $person->update();


    However, there is a way to modify the values of the keys. You MUST use array type and set a key name for each entry.

    This will work:
    $person = Mango::factory('person', array('_id' => MongoId))->load();
    $person->siblings['eldest'] = array('name' => 'Mary', 'last_name' => 'Smith');
    $person->create();
    $person->siblings['eldest'] = array('name' => 'Mary Jane', 'last_name' => 'Smith');
    $person->update();
    $person->siblings['eldest']['name'] = 'Maria';
    $person->update();
    $person->siblings['eldest']['middle_name'] = 'Jane'; // Adding new key is possible
    $person->update();
    // Be careful when copying objects
    $person->siblings['youngest'] = $person->siblings['eldest']; // Copying existing object
    $person->siblings['youngest']['name'] = 'Joe'; // This updates the key 'name' for $person->siblings['eldest'] as well
    $person->siblings['eldest']['name'] = 'Maryann'; // This updates the key 'name' for $person->siblings['youngest'] as well
    $person->update();


    My conclusion is that if you want to have an object that you think you are going to edit, then use arrays with a non-numerical keyname, but if you are collecting values (probably a log) then using sets is fine. When copying objects around be careful if you are updating the values, you can get some surprises there!

    Thanks,

    Nano.
  • It's a (very annoying) MongoDB bug. I said it before already.

    Posted By: Wouter

    1) Updating sets using dotnotated array indeces doesn't work properly in Mongo. Bug is reported here: http://jira.mongodb.org/browse/SERVER-181



    I'm always pushing the developers to fix this bug, but in the end, they decide on the roadmap, not me :-).

    Due to this bug, Mango_Set has some strange behaviour with updating. Only when they have fixed this bug, and when I know how they decided to do so, I can update Mango_Set (I have to know what combinations they allow for $push, $pull and $set).

    Try this in your shell, and you'll notice the bug. It just doesn't accept valid commands.

    > db.example.remove();
    > db.example.insert({_id:1, siblings : [ { name : 'jane', last_name : 'smith' }]});
    > db.example.update({_id:1},{ $set : { 'siblings.0' : { name : 'joe' }}});
    Modifier spec implies existence of an encapsulating object with a name that already represents a non-object, or is referenced in another $set clause
    > db.example.update({_id:1},{ $set : { 'siblings.0.name' : 'joe' }});
    Modifier spec implies existence of an encapsulating object with a name that already represents a non-object, or is referenced in another $set clause


    Finally, please note that Mango supports embedded objects like this:

    Your person model:
    class Model_Person extends Mango {

    protected $_fields = array(
    'siblings' => array('type'=>'has_many')
    );

    }


    Your sibling model (new!):
    class Model_Sibling extends Mango {

    protected $_embedded = TRUE;

    protected $_fields = array(
    'first_name' => array('type' => 'string'),
    'last_name' => array('type' => 'string')
    );
    }


    Using it:
    $person = Mango::factory('person');

    $sibling = Mango::factory('sibling', array(
    'first_name' => 'mary',
    'last_name' => 'smith'
    ));

    $person->siblings[] = $sibling;
    // $person->add($sibling); is also valid

    $person->create();

    $person = Mango::factory('person', array(
    '_id' => $person->_id
    ))->load();

    $person->siblings[0]->first_name = 'john';


    Please note; the bugs you encountered remain, but when Sibling is a real Mango model, you get all the Mango features, like validation.
  • @Wouter

    Thank you for your post, always a good learning source.

    Is this a typo? (I haven't dig too much into extensions yet)

    http://github.com/Wouterrr/MangoDB/blob/master/classes/mango.php#L514

    Shouldn't it be?
    protected function _set_model_definition(array $definition)
    {
    if(isset($definition['_fields']))
    {
    $this->_fields = array_merge($this->_fields,$definition['_fields']);
    }

    if(isset($definition['_relations']))
    {
    $this->_relations = array_merge($this->_relations,$definition['_relations']);
    }
    }


    Or is _has_one the only relation accepted when using _set_model_definition?

    Thanks,

    Nano.
  • That's a bug! And it's gone now! :-)

    Thanks
  • Hi Wouter,

    I didn't see the count method for collections implemented on mango, thus, this is what I have done and it worked for me.

    Method count on mango.php:
    /**
    * Return the count of a (set of) document(s) from the database
    *
    * @param array specify additional criteria
    * @return int the result from count
    */
    public function count(array $criteria = array())
    {
    // Not sure if should restrict it to embedded
    if($this->_embedded)
    {
    throw new Mango_Exception(':name model is embedded and cannot be loaded from database',
    array(':name' => $this->_model));
    }

    $criteria += $this->changed(FALSE);

    if ( isset($criteria['_id']))
    {
    // if ID is set, we don't need any other value
    $criteria = array(
    '_id' => $criteria['_id']
    );
    }

    // resets $this->_changed array
    $this->clear();

    return $this->_db->count($this->_collection,$criteria);
    }


    And mangodb.php also needed some adjustments because count expects only 1 parameter:
    Replace this:
    public function count( $collection_name, array $query = array(), array $fields = array() )
    {
    return $this->_call('count', array(
    'collection_name' => $collection_name,
    'query' => $query,
    'fields' => $fields
    ));
    }


    With this one:
    public function count( $collection_name, array $query = array())
    {
    return $this->_call('count', array(
    'collection_name' => $collection_name,
    'query' => $query
    ));
    }


    And also at the __call method:
    case 'count':
    $r = $c->count($query,$fields);


    for this one:
    case 'count':
    $r = $c->count($query);


    And its usage (assuming there is a log model with an field called date, which preferable is an index for faster responses):
    $visits = Mango::factory('log', array('date' => '2010-01-01'))->count();


    Sorry I have not created a patch, kind of lazy :)

    Let me know your thoughts.

    Thanks,

    Nano.
  • I already fixed the count method in the MangoDB class 4 days ago (see: http://github.com/Wouterrr/MangoDB/commit/c9179a7578ada860ef0676b1c884be080048feda).

    I'm still thinking if it makes sense to add a count method (and/or a distinct method) to an ORM library; is it logic that belongs on ORM level?!

    On another note, the MongoDB team just released 1.3 (unstable) which supports $set with array indices and $unset, so expect some updates soon!
  • I somehow agree that having a count at the ORM-like level might not make sense, but Mango is not a traditional ORM library, it deals with a different type of database. To me the count method for MongoDB should be considered because of the performance difference. If I don't have a method for getting the counts then I have to retrieve all the objects and after that do a $total = count($model_results) which consumes memory (even if limiting the fields to be retrieved). If we are talking about counting entries in the order of magnitude of thousand of them, then I think it could matter.

    In addition, I feel count should be considered because of the nature of MongoDB, they provide that API method because the database favors that kind of queries. The count is not done via find, which in relational dbs the count is done via select statements. My 2 cents.

    What do you consider could be an alternative to get the counts for many objects right now? Is there a way to do some kind of raw calls to db from Mango?

    Thanks,

    Nano.
  • On another note, the MongoDB team just released 1.3 (unstable) which supports $set with array indices and $unset, so expect some updates soon!



    I just love new versions and upgrades. Bravo for all the great work (and support) Wouter !!!! :^)
  • @Nano: The MangoDB class already supports the count method. I'm only wondering if it should be included in the Mango ORM layer.

    This will always work:
    $db = MangoDB::instance(); // or $log->db();
    $visits = $db->count('logs', array('date'=>'2010-01-01'));
  • @Wouter

    Totally agree, no need to add the method to Mango. MangoDB is good enough. Thanks, it works like a charm!

    Cheers for the great work! Eager to see the new changes.

    Nano.
  • I was eagerly awaiting the $unset and the $set on array indices features, so although MongoDB 1.3 is still a development version, I did add support to Mango for those features (+ I did some code cleanup). Please update your MongoDB installation to 1.3 to be able to use the new features.

    There is some testing to do, as it can get pretty complex (eg with nested arrays and sets), and MongoDB does not support some combinations of modifiers on a single field. Also, there could be bugs in Mango and in MongoDB, so if you run into something strange, post it here, and we'll try to look for an answer :-).
  • Hi Wouter,

    Sure, I will test them out, both, new MongoDB and Mango & MangoDB modules.

    Do you have a recommendation for a web hosting company that can support MongoDB? I will need one in few months once I start pushing my development to alpha stage. Any hints will be appreciated.

    Thanks,

    Nano.
  • @wouter: wow! that's bunch load of commits! you like that space after the parenthesis in if huh? :-)
    Can you update mangodemo with some new examples? :P

    @nano: I'd like to know about one too. Webfaction seems nice and you can install Mongo, but they won't support it.
  • Any VPS (slicehost, linode, vps.net) will do :-). I don't know about others, but you can always ask around on the MongoDB mailinglist (http://groups.google.com/group/mongodb-user) for help.

    Edit: I added another simple $unset/$set with array indices demo to MangoDemo, but let me know if you have any requests.
  • I cannot remove an element from a set. I am trying this but doesn't work. ($model->my_set[0] already exists);
    $model = Mango::factory('test')->load(1);
    unset($model->my_set[0]);
    $model->update();


    Model:
    class Model_Test extends Mango {
    protected $_fields = array(
    'my_set' => array(
    'type'=>'set'
    )
    );
    }


    Any hints?

    Thanks.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion