Skip to content
This repository has been archived by the owner on Jun 29, 2024. It is now read-only.

Mongo_Document

colinmollenhour edited this page Feb 27, 2012 · 9 revisions

This class objectifies a Mongo document and can be used with one of the following design patterns:

1. Table Data Gateway pattern

class Model_Post extends Mongo_Document {
  protected $name = 'posts';
  // All model-related code here
}
$post = Mongo_Document::factory('post', $post_id);

2. Row Data Gateway pattern:

class Model_Post_Collection extends Mongo_Collection {
  protected $name = 'posts';
  // Collection-related code here
}
class Model_Post extends Mongo_Document {
  // Document-related code here
}
$post = Mongo_Document::factory('post', $post_id);

The following examples could be used with either pattern with no differences in usage. The Row Data Gateway pattern is recommended
for more complex models to improve code organization while the Table Data Gateway pattern is recommended for simpler models.

  class Model_Document extends Mongo_Document {
    public $name = 'test';
  }
  $document = new Model_Document();
  $document->name = 'Mongo';
  $document->type = 'db';
  $document->save();
  // db.test.save({"name":"Mongo","type":"db"});

The “_id” field is aliased to “id” by default. Other aliases can also be defined using the $_aliases protected property. Aliases can be used anywhere that a field name can be used including dot-notation for nesting.

  $id = $document->id;  // MongoId
  $document->load('{name:"Mongo"}');
  // db.test.findOne({"name":"Mongo"});

Methods which are intended to be overridden are {before,after}_{save,load,delete} so that special actions may be taken when these events occur:

  public function before_save()
  {
    $this->inc('visits');
    $this->last_visit = time();
  }

When a document is saved, update will be used if the document already exists, otherwise insert will be used, determined by the presence of an _id. A document can be modified without being loaded from the database if an _id is passed to the constructor:

  $doc = new Model_Document($id);

Atomic operations and updates are not executed until save() is called and operations are chainable. Example:

  $doc->inc('uses.boing');
      ->push('used',array('type' => 'sound', 'desc' => 'boing'));
  $doc->inc('uses.bonk');
      ->push('used',array('type' => 'sound', 'desc' => 'bonk'));
      ->save();
  // db.test.update(
  //   {"_id":"one"},
  //   {"$inc":{"uses.boing":1,"uses.bonk":1},"$pushAll":{"used":[{"type":"sound","desc":"boing"},{"type":"sound","desc":"bonk"}]}}
  // );

Documents are loaded lazily so if a property is accessed and the document is not yet loaded, it will be loaded on the first property access:

  echo "$doc->name rocks!";
  // Mongo rocks!

Documents are reloaded when accessing a property that was modified with an operator and then saved:

  in_array($doc->roles,'admin');
  // TRUE
  $doc->pull('roles','admin');
  in_array($doc->roles,'admin');
  // TRUE
  $doc->save();
  in_array($doc->roles,'admin');
  // FALSE

Documents can have references to other documents which will be loaded lazily. However, referenced documents are not saved automatically.

  class Model_Post extends Mongo_Document {
    protected $name = 'posts';
    protected $_references = array(
      'user'      => array('model' => 'user'),
      'comments'  => array('model' => 'comment', 'foreign_field' => 'post_id')
    );

  }

  class Model_User extends Mongo_Document {
    protected $name = 'users';
  }

  class Model_Comment extends Mongo_Document {
    protected $name = 'comments';
  }

  $user = Mongo_Document::factory('user')->set('id','colin')->set('email','[email protected]')->save();
  // db.users.save({"_id":"colin","email":"[email protected]"})
  $post = Mongo_Document::factory('post');
  $post->user = $user;
  $post->title = 'MongoDb';
  $post->save()
  // db.posts.save({"_id":Object,"_user":"colin","title":"MongoDb"})

  $post = new Model_Post($id);
  $post->_user;  
  // "colin" - the post was loaded lazily.
  $post->user->id;
  // "colin" - the user object was created lazily but not loaded.
  $post->user->email;
  // "[email protected]" - now the user document was loaded as well.
  foreach($post->comments as $comment){ ... }
  // db.comments.find({"post_id":$post->id});
Clone this wiki locally