|
NAMEMongoose::Intro - an introductionMOTIVATIONThis module is an attempt to bring together the full power of Moose into the MongoDB database.Before using this module you should take a little time to read on MongoDB. REQUIREMENTSTo use this module, you need:MongoDB installed somewhere in your network.Grab a pre-built copy for your OS from here <http://www.mongodb.org/downloads>, or build it from sources <http://www.mongodb.org/display/DOCS/Source+Code>.After intalling the software, start the Mongo daemon: mongod -dbpath /path/to/data The MongoDB Perl drivercpan MongoDB cpan Mongoose Set the "MONGOOSEDB" environment variable to your MongoDB connection in case it's not standard (localhost). make export MONGOOSEDB=host,mongodb://localhost,db_name,mytestdb make test make install Moose classesCreate some Moose classes to start using Mongoose;package MyClass; use Moose; with 'Mongoose::Document'; has 'yada' => ( is=>'rw', isa=>'Str' ); FEATURESSome of Mongoose features:
CAVEATS
GETTING STARTEDThere are only two steps to start using Mongoose in your code:1) Create at least one class that consumes a Mongoose::Document role. 2) Connect to a Mongo database in your main program. MongoDB does not require you to previously create a database, a collection or a document schema for your collection. This is done on the fly for you. To make your Moose classes "Mongoable", all they need is to consume either one of two roles: Mongoose::Document or Mongoose::EmbeddedDocument. Read on for details on the difference. Turning your classes into Mongo DocumentsThere are two roles to make your Moose class a Mongoose document:* Mongoose::Document * Mongoose::EmbeddedDocument The difference between these roles lies in the way objects of different classes will be joined and stored (collapsed) into the DB. Read the MongoDB docs <http://http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-EmbeddingandLinking> if you don't understand the difference. Document Akin to a row in the relational model. Objects are stored into independent collections. Relationships are stored using references, MongoDB's foreign key system. EmbbededDocument Tells Mongoose to store your class as an embedded document, inside a parent document. This is usually faster than using document-to-document reference joins. But it's not meant for object reuse by foreign documents. Methods you get when using the Document rolesBoth "Document" and "EmbeddedDocument" will import into your class the following methods:save Saves the current object to the database, inserting the document if needed. $person->save; delete Deletes the corresponding document from the database. $person->delete; find Wraps MongoDB's find method to return a cursor that expands data into objects. my $cursor = Person->find({ age => { '$lt' => 30 } }); find_one Finds exactly one document. my $jack = Person->find_one({ first_name => 'Jack' }); collection Returns the MongoDB::Collection object supporting this class. It's a way to switch quickly back to MongoDB hash documents. Person->find_one({ name=>'thyself' }); # isa Person # whereas Person->collection->find_one({ name=>'thyself' }); # ref = HASH _id Not really a method but an attribute used by Mongoose (and MongoDB). Contains a unique BSON::OID instance. Deleting or modifying this attribute may cause your object to be re-inserted on the next "save", instead of being updated. The Default EngineMongoose comes with a default engine, Mongoose::Engine that takes care of expanding and collapsing objects to and from the Mongo database.Collapsing Collapsing is the process of serializing classes. Your Moose objects are collapsed by unblessing them until they become a hash. Relationships are mantained in the process. Expanding Expansion is the process of inflating Mongo documents (plain hashes) into Moose objects. This is done by inspecting the class attribute metadata. The engine tries to do it's best identifying data types. The document is then "bless"ed into your class. This is faster than calling "new", but also means that no special class or attribute methods will be fired, such as default values, setters, triggers or coercion. You've been warned. Naturally, there are many cases where this guesswork is not enough. These may be addressed in the future using attribute traits, but should be fine for most trivial classes. CONFIGURATIONMongoose roles are role parameterized for greater flexibility.Collection namingYou can control the collection name for an individual class this way:package My::Mumbo::Jumbo::Class; use Moose; with 'Mongoose::Document' => { -collection_name => 'mumbo_jumbo' }; Global collection naming stategyBy default, Mongoose will turn package names into collections this way:Package name | Collection name ----------------------+---------------------- Person | person Humpty::Dumpty | humpty_dumpty HumptyDumpty | humpty_dumpty MyApp::Schema::Jumbo | my_app_schema_jumbo You can change this standard anytime, by setting the "Mongoose::naming" anonymous sub to something of your liking: # remove prefix and return # a lower case collection name Mongoose->naming( sub{ my $pkg = shift; $pkg =~ s{^MyApp::Schema::}{}g; return lc $pkg; }); Primary keysThe standard way MongoDB deals with primary keys is by using the "_id" attribute. By default, a BSON::OID is assigned to each object you commit to the database with "save".Checkout this Devel::REPL example: $ re.pl > use Person; > my $hurley = Person->new(name=>'Hurley'); $Person1 = Person=HASH(0x102099d08); > $hurley->dump; $VAR1 = bless( { 'name' => 'Hurley' }, 'Person' ); > $hurley->save; 4c683525a74100a8df000000 > $hurley->dump; $VAR1 = bless( { _id => bless( { 'oid' => '4c683525a74100a8df000000' }, 'BSON::OID' ), name => 'Hurley' }, 'Person' ); This is pretty standard MongoDB stuff. Now, for a more control over your primary key, use the role parameter "-pk". package BankAccount; use Moose; with 'Mongoose::Document' => { -pk => [qw/ drivers_license /] }; has 'drivers_license' => (is=>'rw', isa=>'Int' ); That way, updates use the "drivers_license" field and inserts will fail if the primary key exists. (But be sure to set a unique index on your primary key.) Schema ChangesIf you first had a class definition as such:package Author; use Moose; with 'Mongoose::Document'; has 'name' => ( is => 'rw', isa => 'Str' ); Saved some objects into the DB: Author->new( name => 'Mike Old Schema' )->save; Then, later on, changed it to: has 'first_name' => ( is => 'rw', isa => 'Str' ); When reading from the database, at expansion time, since the MongoDB document is just blessed into your class the old attribute will be loaded as if nothing had happened: # load old schema document using the new schema: my $obj = Author->find_one({ name => 'Mike Old Schema' }); print Dump $obj; # prints --- !!perl/hash:MyTestApp::Schema::Author _id: !!perl/hash:BSON::OID oid: 4c723348a741001455000000 name: Mike Old Schema At this time, no "BUILD" or "BUILDARGS" methods are called, which could be used to rearrange the object into the new schema. On the meanwhile, you can always invoke an "alignment" method after loading the data, or do a bulk migration: Author->find->each( sub{ my $obj = shift; $obj->first_name( delete $obj->{name} ); $obj->save; }); You can also check the expanded() method where you can manipulate your just expanded object. SEE ALSONow head on to the Mongoose::Cookbook.
Visit the GSP FreeBSD Man Page Interface. |