NAME
Mongoose::Cookbook - recipes, recipes
VERSION
version 0.01_03
RECIPES
Here we go.
Connecting to MongoDB
Then connect to a database anywhere before starting to use your classes.
use Mongoose;
Mongoose->db( 'mydb'); # looks for a localhost connection
# or, for more control:
Mongoose->db(
host=>'mongodb://data.server:4000',
db_name=>'mydb'
);
This is done globally here for simplicity sake, but a more object oriented notation is also supported.
Connecting to more than one database
This is a work in progress. Right now this syntax is supported:
Mongoose->db( class=>'Person', db_name=>'mydbone', ... );
Mongoose->db( class=>'Address', db_name=>'mydbtwo', ... );
But this will most certainly change.
Loading a Schema
To quickly load your classes, use the load_schema
method:
package main;
Mongoose->load_schema( search_path=>'MyApp::Schema', shorten=>1 );
Use it only once in your program. Your modules will be required and may be used from anywhere else.
The shorten
option will alias MyApp::Schema::MyClass
into MyClass
for your convenience.
Preventing attributes from being stored
In case your class has attributes you don't want to store in the database.
package Person;
use Moose;
with 'Mongoose::Document';
has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
has 'age' => ( is => 'rw', isa => 'Int', default => 40 );
has 'salary' => ( is => 'rw', isa => 'Int', traits => ['DoNotSerialize'] );
One-to-many Relationships
This can be accomplished several ways.
ArrayRef
Use the ArrayRef
Moose type.
package Person;
use Moose;
with 'Mongoose::Document';
has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
has 'accounts' => ( is => 'rw', isa => 'ArrayRef[Account]' );
Then, define the Account class, either as a document or embedded document, depending on how you want it stored.
package Address;
use Moose;
with Mongoose::EmbeddedDocument;
has 'amount' => ...;
But this has a memory and performance cost, since all related rows will be loaded in memory during object expansion.
To avoid loading related rows, use a Mongoose::Join parameterized type.
Mongoose::Join
Establishing a Mongoose::Join relationship will load relationships lazily:
package Person;
use Moose; with 'Mongoose::Document';
has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
has 'accounts' => ( is => 'rw', isa => 'Mongoose::Join[Account]' );
Then retrieve data with a cursor:
my $large_acc = $person->accounts->find({ amount => { '$gt' => 100000 } });
while( my $account = $large_acc->next ) {
...
}
Sugar for Defining Relationships
Use Mongoose::Class instead of Moose
.
package Article;
use Mongoose::Class; with 'Mongoose::Document';
has 'title' => ( is=>'rw', isa=>'Str', required=>1 );
has_one 'author' => 'Author';
has_many 'comments' => 'Comment';
belongs_to => 'Account';
Normalizing a Relationship
Normalization is a relational concept, not natural to the document-oriented MongoDB, but an useful approach that should sometimes be taken into consideration.
Sometimes it may just be more adequate than storing relationships directly in objects:
package Authorship;
has_one 'author' => 'Author';
has_many 'articles' => 'Article';
package main;
# create
my $authorship = Authorship->new;
$authorship->author( Author->new );
$authorship->articles->add( Article->new );
$authorship->articles->add( Article->new );
# find
my $articles = Authorship->find_one({ author=>$author->_id });
while( my $article = $articles->next ) {
...
}
Package aliasing
To make a long package name shorter, use:
package My::Mumbo::Jumbo::Class;
with 'Mongoose::Document' => {
-as => 'Mumbo',
};
# then in your code
my $obj = Mumbo->find_one({ flavor=>'gum' })
print ref $obj;
# prints 'My::Mumbo::Jumbo::Class'
print $obj->isa('Mumbo')
# prints 1
Method aliasing
In case you don't want a find_one
or save
method polluting your class.
package BankAccount;
with 'Mongoose::Document' => {
-alias => { 'find_one' => '_find_one' },
-excludes => { 'find_one' },
};