Voyage: Persisting Objects in Document Databases
Tips and Tricks
This chapter contains some tips and tricks that people collected over the years. It was written by Sabina Manaa.
How to query for an object by id?
If you know the _id value, you initialize an OID with this and query for it.
Note that both are equivalent:
Or you have an instance (in this example of Person
) which is in a root collection, then you ask it for its voyageId and use it in your query. The following assumes that you have a Trips
root collection and a Persons
root collection. The trip has an embedded receipts
collection. Receipts have a description
. The query asks for all trips of the given person with at least one receipt with the description aString
.
Not yet supported mongo commands
Indexes
It is not yet possible to create and remove indexes from voyage, but you can use OSProcess.
Assume you have a database named myDB
with a collection named Trips
.
The trips have an embedded collection with receipts. The receipts have an attribute named description
.
Then you can create an index on description with
Remove all indexes on the Trips collection with:
Backup
It is not yet possible to create backup from voyage, so use
Please see the mongo documentation for mongo commands, especially the --eval
command.
Useful mongo commands
Use “.explain()” in the mongo console to ensure that your query indeed uses the index.
Example:
Create an index on an embedded attribute (description
):
Query for it and call explain. We see, that only 2 documents were scanned. > db.Trips.find({"receipts.description":"a"}).explain("executionStats") { "cursor" : "BtreeCursor receipts.receiptDescription_1", "isMultiKey" : true, "n" : 2, "nscannedObjects" : 2, "nscanned" : 2, "nscannedObjectsAllPlans" : 2, "nscannedAllPlans" : 2, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 0, "indexBounds" : { "receipts.receiptDescription" : [ [ "a", "a" ] ] }, "allPlans" : [ { "cursor" : "BtreeCursor receipts.receiptDescription_1", "n" : 2, "nscannedObjects" : 2, "nscanned" : 2, "indexBounds" : { "receipts.receiptDescription" : [ [ "a", "a" ] ] } } ], "server" : "MacBook-Pro-Sabine.local:27017" } ]]]
Now, remove the index
Query again, all documents were scanned.
Storing instances of Date in Mongo
A known issue of mongo is Mongo that it does not difference between Date
and DateAndTime
, so even if you commit a Date
, you will get back a DateAndTime
. You have to transform it back to Date
manually when materializing the object.
Database design
Often you objects do not form a simple tree but a graph with cycles. For example you could have persons which are pointing to their trips and each trip knows about its person (Person <->>Trip
). If you create a root Collection with Persons and a Root collection with Trips, you avoid endless loops to be generated (see chapter 1.2).
This is an example for a trip
pointing to a person
which is in another root collection and another root collection, paymentMethod
. Note that the receipt also points back to the trip, which does not create a loop.
The corresponding person
points to all its trips
and to its company
.
If your domain has strictly delimited areas, e.g. clients, you could think about creating one repository per area (client).
Retrieving data
One question is if it possible to retrieve data from Mongo collection even if the database was not created via Voyage. Yes it is possible. Here is the solution.
First we create a class MyClass
with two class side methods:
Also, to properly read the data one should add instance variables depending on what is in the database.
For example if we have the following information stored in the database:
In this case MyClass
should have instanceVariables: item
, qty
and tags
and accessors.
Then we define the following description on the class side
After that one can connect to database and get the information.