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' },
};