NAME¶
MongoDBx::Class::Tutorial - Tutorial for using MongoDBx::Class
VERSION¶
version 1.030002
INTRODUCTION¶
MongoDBx::Class is a flexible object relational mapper (ORM) for MongoDB
databases. Before reading this tutorial, please read "DESCRIPTION"
in MongoDBx::Class.
CREATING DOCUMENT CLASSES¶
The first step towards using MongoDBx::Class is creating document classes. Let's
say your application is called MyApp, and that it reviews novels by popular
authors. Every novel has a title (its name), the full name of its author, its
release year, a synopsis, the date the novel was added to the database, a list
of tags categorizing the novel, a list of related novels, and zero or more
reviews.
MongoDBx::Class provides you with a flexible foundation for building classes
that represent our proposed database schema and the relationships (or
"joins") between these classes. This foundation is provided by three
modules:
- •
- MongoDBx::Class::Moose - intended to be used by document classes in place
of Moose. It provides Moose, and all needed relationship types, in the
form of Moose attributes.
- •
- MongoDBx::Class::Document - a Moose role intended to be consumed by
document classes. When documents are expanded from the database, this role
is applied to them and thus provides them some common attributes and
methods.
- •
- MongoDBx::Class::EmbeddedDocument - a Moose role intended to be consumed
by embedded document classes. When embedded documents are found inside
other documents and expanded, this role is applied to them and thus
provides them some common attributes and methods.
Before actually creating document classes, we need to design our schema. The
most common question to tackle when designing a schema is when and how to use
references, and when to simply embed documents. Refer to
<
http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Embedvs.Reference>
for some information about schema design in MongoDB.
Our database schema will be like this:
- •
- Every novel will be represented by a document in the 'novels'
collection.
- •
- An author's name will be stored in the novel's document as an embedded
document that has first and last names, and possibly a middle name.
- •
- The synopsis of the novel will be stored as a standalone document in the
'synopsis' collection, and will simply reference the novel with a 'novel'
attribute.
- •
- The date and time the novel was added to the database will be stored as a
W3C formatted string which will automatically be converted to a DateTime
object (see MongoDBx::Class::ParsedAttribute::DateTime or read further for
the rationale).
- •
- The list of tags will be stored in the novel document as an array of
embedded documents.
- •
- The list of related novels will be stored in the novel document as an
array of database references to other novels.
- •
- The reviews for every novel are stored as standalone documents in the
'reviews' collection, and will simply reference the novel with a 'novel'
attribute.
Let's look at a possible JSON representation of a novel - "The Valley of
Fear" by Sir Arthur Conan Doyle:
# in the 'novels' collection
{
"_id": ObjectId("4cbca90d576fad5916790100"),
"title": "The Valley of Fear",
"year": 1914,
"author": {
"first_name": "Arthur",
"middle_name": "Conan",
"last_name": "Doyle"
},
"added": "2010-01-11T22:12:44+02:00",
"tags": [
{ "category": "mystery", "subcategory": "thriller" },
{ "category": "mystery", "subcategory": "detective" },
{ "category": "crime", "subcategory": "fiction" }
],
"related_novels": [
{ "$ref": "novels", "$id": ObjectId("4cbca90d3a41e35916720100") },
{ "$ref": "novels", "$id": ObjectId("4cbca90d44d8c959167a0100") },
{ "$ref": "novels", "$id": ObjectId("4cbca90d486bbf59166f0100") }
]
}
# in the 'synopsis' collection
{
"_id": ObjectId("4cbca90d699e9a5916670100"),
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"text": "The Valley of Fear is the final Sherlock Holmes novel by Sir Arthur Conan Doyle. The story was first published in the Strand Magazine between September 1914 and May 1915. The first book edition was published in New York on 27 February 1915."
}
# in the 'reviews' collection
{
"_id": ObjectId("4cbca90dfbb2945916740100"),
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Some Guy",
"text": "I really liked it!",
"score": 5
},
{
"_id": ObjectId("4cbca90e0ad57b5916f50100"),
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Some Other Guy",
"text": "It was okay.",
"score": 3
},
{
"_id": ObjectId("4cbca90e0b9c175916c60100"),
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Totally Different Guy",
"text": "Man, that just sucked!",
"score": 1
}
We now need to translate this structure to MongoDBx::Class document classes. As
mentioned before, document classes are Moose classes, but instead of using
Moose, they use MongoDBx::Class::Moose. We'll start with the document class
representing novels:
package MyApp::Schema::Novel;
use MongoDBx::Class::Moose;
use namespace::autoclean;
with 'MongoDBx::Class::Document';
has 'title' => (is => 'ro', isa => 'Str', required => 1, writer => 'set_title');
holds_one 'author' => (is => 'ro', isa => 'MyApp::Schema::PersonName', required => 1, writer => 'set_author');
has 'year' => (is => 'ro', isa => 'Int', predicate => 'has_year', writer => 'set_year');
has 'added' => (is => 'ro', isa => 'DateTime', traits => ['Parsed'], required => 1);
has 'review_count' => (is => 'rw', isa => 'Int', traits => ['Transient'], builder => '_build_review_count');
holds_many 'tags' => (is => 'ro', isa => 'MyApp::Schema::Tag', predicate => 'has_tags');
joins_one 'synopsis' => (is => 'ro', isa => 'Synopsis', coll => 'synopsis', ref => 'novel');
has_many 'related_novels' => (is => 'ro', isa => 'Novel', predicate => 'has_related_novels', writer => 'set_related_novels', clearer => 'clear_related_novels');
joins_many 'reviews' => (is => 'ro', isa => 'Review', coll => 'reviews', ref => 'novel');
sub _build_review_count { shift->reviews->count }
sub print_related_novels {
my $self = shift;
foreach my $other_novel ($self->related_novels) {
print $other_novel->title, ', ',
$other_novel->year, ', ',
$other_novel->author->name, "\n";
}
}
around 'reviews' => sub {
my ($orig, $self) = (shift, shift);
my $cursor = $self->$orig;
return $cursor->sort([ year => -1, title => 1, 'author.last_name' => 1 ]);
};
__PACKAGE__->meta->make_immutable;
Aside from standard Moose usage, we've used some of MongoDBx::Class' built-in
relationship types. Head over to MongoDBx::Class::Moose for a list of provided
relationship types and how they translate to database entries.
In this example, we've used the "holds_one" relationship to denote
that a Novel document entirely holds one embedded PersonName sub-document.
We've used "holds_many" to have Novel documents entirely hold Tag
documents. We've also used "joins_one" to easily find a novel's
synopsis, located in the synopsis collection. "joins_many" was used
to easily find all Review documents located in the reviews collection.
Finally, we've used "has_many" for the list of references to related
novels.
You will notice that when using the "holds_one" and
"holds_many" relationship types, we've given the full package names
to the "isa" option (such as MyApp::Schema::PersonName), while in
other relationship types, we've given the class names only (such as
'Synopsis'). This inconsistency is only temporary, and will change in future
versions, so keep your finger on the pulse.
Of particular interest is the 'added' attribute, for which we've added the
<Parsed|MongoDBx::Class::AttributeTraits::Parsed> attribute trait
(automatically provided with MongoDBx::Class). When adding this trait to an
attribute, MongoDBx::Class looks for a module implementing the
MongoDBx::Class::ParsedAttribute role named like the 'isa' option of the
attribute. In our example, MongoDBx::Class will look for
MongoDBx::Class::ParsedAttribute::DateTime. However, if you're creating your
own ParsedAttribute classes, you need to also pass the 'parser' option. For
example:
has 'added' => (is => 'ro', isa => 'DateTime', traits => ['Parsed'], parser => 'MyApp::ParsedAttribute::MyCoolDateTimeParser', required => 1);
The 'Parsed' trait means that the parser is responsible for expanding this
attribute from the database when loading a document, and for collapsing the
attribute when saving to the database. This is similar to DBIx::Class'
InflateColumn family of classes from the SQL world. You might ask yourself why
we're using a special DateTime parser here, even though MongoDB natively
supports DateTime objects. The following paragraph is taken from
MongoDBx::Class::ParsedAttribute::DateTime's documentation):
While the Perl L<MongoDB> driver already supports L<DateTime> objects
natively, due to a bug with MongoDB, you can't save dates earlier than
the UNIX epoch. This module overcomes this limitation by simply saving
dates as strings and automatically turning them into DateTime objects
(and vica-versa). The DateTime strings are formatted by the L<DateTime::Format::W3CDTF>
module, which parses dates in the format recommended by the W3C. This is
good for web apps, and also makes it easier to edit dates from the
MongoDB shell. But most importantly, it also allows sorting by date.
Also note the 'review_count' attribute, which has the 'Transient' trait. This
trait means the attribute is not to be saved in the database, even though it
is one of the document's attributes. This is useful for calculated attributes,
or any supporting attributes you add to a document class whose state should
not be saved. You should note that if for some reason a document in the
database
does have an attribute marked as transient in the document's
class (for example if you added it to the document manually), the value of
this attribute will also be ignored when the document is read from the
database.
As you can see, the "joins_many" relationship creates a one-to-many
relationship between one document to one or more other documents which can be
considered "child documents". In this example, there is a
one-to-many relationship between a 'novel' document and one or more 'review'
documents. A "joins_many" relationship is implemented with a cursor.
For example, calling the "reviews()" method on a "Novel"
object will generally return a MongoDBx::Class::Cursor object for a
"find()" query that searches for documents in the 'reviews'
collection, whose 'novel' attribute references the "Novel" document.
In the "Novel" class above, you will notice the
"reviews()" method is also modified with Moose's "around"
method modifier. This example illustrates the fact that "joins_many"
is implemented with a cursor. Suppose you know you will always want to call
"reviews()" and get the child documents sorted by date (or other
fields). The above modification simply sorts the cursor before returning it to
the caller. Of course, this is merely an example of the things you can do with
the "joins_many" relationship.
Continuing on, lets create our two embedded document classes. We'll start with
PersonName:
package MyApp::Schema::PersonName;
use MongoDBx::Class::Moose;
use namespace::autoclean;
with 'MongoDBx::Class::EmbeddedDocument';
has 'first_name' => (is => 'ro', isa => 'Str', required => 1, writer => 'set_first_name');
has 'middle_name' => (is => 'ro', isa => 'Str', predicate => 'has_middle_name', writer => 'set_middle_name');
has 'last_name' => (is => 'ro', isa => 'Str', required => 1, writer => 'set_last_name');
sub name {
my $self = shift;
my $name = $self->first_name;
$name .= ' '.$self->middle_name if $self->has_middle_name;
$name .= ' '.$self->last_name;
return $name;
}
__PACKAGE__->meta->make_immutable;
This is a very simple class, with no relationships. We use the
"name()" method to easily print a person's full name.
On to the Tag document class:
package MyApp::Schema::Tag;
use MongoDBx::Class::Moose;
use namespace::autoclean;
with 'MongoDBx::Class::EmbeddedDocument';
has 'category' => (is => 'ro', isa => 'Str', required => 1);
has 'subcategory' => (is => 'ro', isa => 'Str', required => 1);
__PACKAGE__->meta->make_immutable;
Again, this is a very simple example. Embedded documents will often be as simple
as that.
We have two document classes left. The first is the Synopsis class:
package MyApp::Schema::Synopsis;
use MongoDBx::Class::Moose;
use namespace::autoclean;
with 'MongoDBx::Class::Document';
belongs_to 'novel' => (is => 'ro', isa => 'Novel', required => 1);
has 'text' => (is => 'ro', isa => 'Str', writer => 'set_text', required => 1);
__PACKAGE__->meta->make_immutable;
Here, we've used "belongs_to" to signify a Synopsis document belongs
to a Novel document. Every Synopsis document has a 'novel' attribute which
references the parent Novel document.
Only the Review class is left:
package MyApp::Schema::Review;
use MongoDBx::Class::Moose;
use namespace::autoclean;
with 'MongoDBx::Class::Document';
belongs_to 'novel' => (is => 'ro', isa => 'Novel', required => 1);
has 'reviewer' => (is => 'ro', isa => 'Str', required => 1);
has 'text' => (is => 'ro', isa => 'Str', required => 1);
has 'score' => (is => 'ro', isa => 'Int', predicate => 'has_score');
__PACKAGE__->meta->make_immutable;
That wraps up our document classes. Before we continue, it is important to note
that MongoDBx::Class' ability to identify the class of a document is currently
reliant on the existance of a '_class' attribute in every document in the
database (as described in "CAVEATS AND THINGS TO CONSIDER" in
MongoDBx::Class). So, looking at the JSON representations from before, we need
to modify the representations like so:
# in the 'novels' collection
{
"_id": ObjectId("4cbca90d576fad5916790100"),
"_class": "Novel",
"title": "The Valley of Fear",
"year": 1914,
"author": {
"first_name": "Arthur",
"middle_name": "Conan",
"last_name": "Doyle"
},
"added": "2010-01-11T22:12:44+02:00",
"tags": [
{ "category": "mystery", "subcategory": "thriller" },
{ "category": "mystery", "subcategory": "detective" },
{ "category": "crime", "subcategory": "fiction" }
],
"related_novels": [
{ "$ref": "novels", "$id": ObjectId("4cbca90d3a41e35916720100") },
{ "$ref": "novels", "$id": ObjectId("4cbca90d44d8c959167a0100") },
{ "$ref": "novels", "$id": ObjectId("4cbca90d486bbf59166f0100") }
]
}
# in the 'synopsis' collection
{
"_id": ObjectId("4cbca90d699e9a5916670100"),
"_class": "Synopsis",
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"text": "The Valley of Fear is the final Sherlock Holmes novel by Sir Arthur Conan Doyle. The story was first published in the Strand Magazine between September 1914 and May 1915. The first book edition was published in New York on 27 February 1915."
}
# in the 'reviews' collection
{
"_id": ObjectId("4cbca90dfbb2945916740100"),
"_class": "Review",
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Some Guy",
"text": "I really liked it!",
"score": 5
},
{
"_id": ObjectId("4cbca90e0ad57b5916f50100"),
"_class": "Review",
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Some Other Guy",
"text": "It was okay.",
"score": 3
},
{
"_id": ObjectId("4cbca90e0b9c175916c60100"),
"_class": "Review",
"novel": { "$ref": "novels", "$id": ObjectId("4cbca90d576fad5916790100") },
"reviewer": "Totally Different Guy",
"text": "Man, that just sucked!",
"score": 1
}
You will notice that it is not required to add the '_class' attribute to
embedded documents, only to standalone documents. The reason for the '_class'
requirement is the fact that MongoDBx::Class doesn't enforce one collection
for every document class. Every collection can have documents of one or more
classes, and documents of the same class can be stored in one or more
collections, even databases.
LOADING MongoDBx::Class AND CONNECTING TO A MongoDB SERVER¶
The next step is loading the schema we've just created, and connecting to a
MongoDB server:
my $dbx = MongoDBx::Class->new(namespace => 'MyApp::Schema');
We need to pass the namespace of our schema to MongoDBx::Class. It will attempt
to automatically load every document class under that namespace, and will
return a MongoDBx::Class object back.
We then initiate a connection to a server:
my $conn = $dbx->connect();
We don't pass anything to the "connect()" method, so it attempts to
connect to a MongoDB server running on 'localhost', on the default 27017 port.
We can connect to a specific server like so:
my $conn = $dbx->connect(host => $host, port => $port);
The connect method accepts any of the options that the "new()" method
in MongoDB::Connection accepts, plus the new 'safe' boolean attribute. Passing
a true value for this attribute causes MongoDBx::Class to automatically enable
the 'pass' option to all insert/update/delete operations performed on the
database, so we don't need to pass "{ safe => 1 }" to the
"insert()", "update()" methods, etc. The safe option is
actually required in order to autoamtically expand/collapse documents, so
you'd probably want to enable it, but it is kept disabled by default for
compatibility with the original MongoDB module.
The "connect()" method returns a MongoDBx::Class::Connection object.
NOTE: versions prior to 0.7 stored the returned connection object as the 'conn'
attribute of the $dbx variable. This behavior has been dropped in version 0.7
in order to be consistent with MongoDB and allowing multiple connections.
Now that we have our connection object, we can get a database object:
$conn->get_database('whatever'); # also simply $conn->whatever
INSERTING DOCUMENTS¶
Now the we've loaded our schema and connected to a server, we can start using
MongoDBx::Class. Basically, our usage will not differ greatly from direct
MongoDB usage, as MonogDBx::Class simply extends MongoDB. The biggest
difference between directly using MongoDB and using MongoDBx::Class, is the
automatic expanding and collapsing of documents. Documents are automatically
expanded when inserting documents only if the "safe" option is on,
as mentioned in the previous section.
Let's create a novel document:
my $db = $conn->get_database('myapp');
my $novels_coll = $db->get_collection('novels');
my $novel = $novels_coll->insert({
_class => 'Novel',
title => 'The Valley of Fear',
year => 1914,
author => {
first_name => 'Arthur',
middle_name => 'Conan',
last_name => 'Doyle',
},
added => DateTime->now(time_zone => 'Asia/Jerusalem'),
tags => [
{ category => 'mystery', subcategory => 'thriller' },
{ category => 'mystery', subcategory => 'detective' },
{ category => 'crime', subcategory => 'fiction' },
],
});
Notice that when inserting the novel document, we've directly inserted the
PersonName embedded document and the Tags embedded documents as hash-refs.
This insert, which was safe (since the 'safe' attribute of our connection object
had a true value), returns the novel document after expansion:
$novel->author->name; # prints 'Arthur Conan Doyle'
If the insert was unsafe, we'd just get the MongoDB::OID of the document back.
But note that you can't get the OID object and immediately attempt to load the
document with it, as you can't predict the order in which MongoDB will perform
asynchronous operations.
Lets insert our synopsis now:
my $synopsis = $db->synopsis->insert({
_class => 'Synopsis',
novel => $novel,
text => "The Valley of Fear is the final Sherlock Holmes novel by Sir Arthur Conan Doyle. The story was first published in the Strand Magazine between September 1914 and May 1915. The first book edition was published in New York on 27 February 1915.",
});
Notice how we've passed the $novel object directly as the 'novel' attribute.
When inserting, MongoDBx::Class will automatically save it as a DBRef object
for us.
Now for our reviews:
my @reviews = $conn->get_collection('reviews')->batch_insert([
{
_class => 'Review',
novel => $novel,
reviewer => 'Some Guy',
text => 'I really liked it!',
score => 5,
},
{
_class => 'Review',
novel => $novel,
reviewer => 'Some Other Guy',
text => 'It was okay.',
score => 3,
},
{
_class => 'Review',
novel => $novel,
reviewer => 'Totally Different Guy',
text => 'Man, that just sucked!',
score => 1,
}
]);
my ($total_score, $avg_score) = (0, 0);
foreach (@reviews) {
$total_score += $_->score || 0;
}
$avg_score = $total_score / scalar(@reviews);
print $avg_score; # prints 3
If we now run "$novel->reviews()", we'd get a
MongoDBx::Class::Cursor back. And since we've created a method modification in
the Novel class on this method, this cursor will also be sorted.
foreach ($novel->reviews->all) {
# $_ is now a MyApp::Schema::Review object
print $_->score;
}
SEARCHING DOCUMENTS¶
MongoDBx::Class adds automatic expansion to document searching, plus some
convenient shortcuts. Say we've received the ID of a novel document as input,
and we want to load it. With MongoDB, we'd probably do:
$db->novels->find_one({ _id => MongoDB::OID->new(value => $oid) })
With MongoDBx::Class, we can just do:
$db->novels->find_one($oid);
And $oid can either be the string ID, or a MongoDB::OID object.
If the document is found, and has the '_class' attribute, then it will be
automatically expanded.
my $novel = $db->novels->find_one($oid)
|| die "Oh my god I can't find this, kill me, kill me now";
print $novel->author->name; # again, prints 'Arthur Conan Doyle'
Let's search for reviews written by a certain reviewer:
my $cursor = $db->reviews->find({ reviewer => 'Some Guy' })->sort({ score => -1 }); # the `find` method also has two synonyms: `query` and `search`
This gives a MongoDBx::Class::Cursor back:
print $cursor->count; # prints 1
while (my $review = $cursor->next) {
print $review->novel->title, "\n";
}
Sorting documents is easier. We can sort by a list of ordered attributes like
so:
$cursor->sort([ attr1 => 1, attr2 => 1, attr3 => -1 ]);
UPDATING DOCUMENTS¶
Updating documents is much easier with MongoDBx::Class. There are two ways to
update documents in MongoDBx::Class:
- •
- The older, MongoDB way of using the "update()" method in
MongoDBx::Class::Collection. This is now mostly used to update multiple
documents at once.
- •
- The new, MongoDBx::Class way of using the "update()" method
provided to document classes by MongoDBx::Class::Document. This is used to
update a specific document.
Let's take a look at the first way. Suppose we want to cheat and update all
reviews for "The Valley of Fear" with a score of five:
$db->reviews->update({ 'novel.$id' => $novel->_id }, { '$set' => { score => 5 } }, { multiple => 1 }); # updates are by default singular, so we add the 'multiple' option
This is exactly like using MongoDB::Collection directly. If we're updating a
specific document we've already loaded, however, MongoDBx::Class provides a
much more comfortable way. Instead of doing:
$db->novels->update({ _id => $novel->_id }, { ... })
We can do:
$novel->update({ year => 1915 });
This will effectively invoke a '$set' update like this:
$db->novels->update({ _id => $novel->_id }, { '$set' => { year => 1915 } });
But this isn't really the Moose way of doing things, so MongoDBx::Class gives us
yet another way of updating a document:
$novel->set_year(1915); # we can do this because we've added a 'writer' option to the 'year' attribute
$novel->update;
When invoking "update()" on a document object with no arguments, a
"snapshot" of the document is taken, and the following update is
effectively performed:
$db->novels->update({ _id => $novel->_id }, { title => "The Valley of Fear", year => 1915, ... });
When we pass arguments to the "update()" method (there are two
arguments we can pass, the hash-ref of updates to perform, and the standard
options hash-ref we know from the original "update()" method in
MongoDB::Collection), MongoDBx::Class simply performs a '$set' update on the
passed hash-ref attributes only. So doing this:
$novel->set_year(1915);
$novel->update({ title => 'The Valley of Fearrrrrr' });
Will only result in the 'title' attribute being updated, not the year attribute.
Updating embedded documents is similarly easy:
$novel->author->set_first_name('Sir Arthur');
$novel->update;
REMOVING DOCUMENTS¶
Removing documents with MongoDBx::Class is very easy. Having the document
object, simply call:
$novel->remove;
Or:
$novel->delete;
And this novel document will be removed from the database. Note, however, that
the delete operation does not cascade, so only the novel document is deleted.
The synopsis and reviews are not deleted, and you have to do so manually.
You can still use the original "remove()" method on collections, now
mostly to remove multiple documents:
$db->get_collection('reviews')->remove({ 'novel.$id' => $novel->_id }); # removes are by default multiple
FAQ¶
Can I use more than one database?¶
Yes, you can use as many databases as you like and use the same document classes
across them:
my $data_db = $conn->get_database('myapp_data');
my $user_db = $conn->get_database('myapp_users');
Can I define different document classes to different databases?¶
There currently isn't a way to define individual schemas for different
databases. You can, however, "split" your schema. For example, if
your application has a data DB and a user DB, you can put all the document
classes of the data DB under MyApp::Schema::Data, and all the document classes
of the user DB under MyApp::Schema::User.
What if I want to use the asynchronous AnyMongo driver instead?¶
Currently, MongoDBx::Class only supports the official MongoDB driver, but
support for AnyMongo is planned.
What if I have attributes I don't want to save in the database?¶
MongoDBx::Class does not provide an option like that yet, but will probably do
so in upcoming versions.
I'm not getting document objects but just the document hash-refs, what gives?¶
If, either when searching for documents or creating/updating documents, you are
not receiving expanded document objects back but only the document hash-refs
when searching/updating, or the documents' MongoDB::OIDs when inserting, there
might be a few reasons for this:
- 1. You are not using safe operations: MongoDBx::Class cannot expand
documents when not using safe operations. Either enable the 'safe' option
when inserting/updating, or enable the safe option globally when connecting
using MongoDBx::Class's "connect()" method.
- 2. The document hash-ref does not define the '_class' attribute:
MongoDBx::Class cannot expand document without knowing to which document
class the document belongs. Therefore, documents in the MongoDB database
must have the '_class' attribute.
- 3. The '_class' attribute is wrong or does not exist: If the document has
the '_class' attribute and you're still not getting document objects back,
then MongoDBx::Class probably can't find the document class. This might be
because the class name is wrong, or the class was not found when loading
MongoDBx::Class. If that is the case, you might wanna take a look at the
"search_dirs" attribute of MongoDBx::Class.
Who framed Roger Rabbit?¶
I framed Roger Rabbit!
WRAP UP¶
You now know how you can use MongoDBx::Class in your applications, and make
MongoDB act like a relational database, without sacrificing its NoSQL nature
and special features.
Before using MongoDBx::Class, please take into account that its alpha software,
and is not ready yet for production use. If you find bugs, please report them
in the usual channels (see "BUGS" in MongoDBx::Class).
AUTHOR¶
Ido Perlmuter, "<ido at ido50.net>"
SUPPORT¶
You can find documentation for this module with the perldoc command.
perldoc MongoDBx::Class::Tutorial
SEE ALSO¶
MongoDBx::Class, MongoDB, <
http://www.mongodb.org/>.
LICENSE AND COPYRIGHT¶
Copyright 2010-2014 Ido Perlmuter.
This program is free software; you can redistribute it and/or modify it under
the terms of either: the GNU General Public License as published by the Free
Software Foundation; or the Artistic License.
See
http://dev.perl.org/licenses/ for more information.