An almost full-featured Morphia sample covering embedded array functionality, written as if CRUD, may be found here.
All that is needed is just one JAR; the latest as I write this is morphia-0.99.1-SNAPSHOT.jar from morphia: A type-safe Java library for MongoDB.
There is no Javadoc solution as yet except to download the sources, then build the Javadoc for yourself.
In a lot of examples, the name of the database and the collection seem totally random and unimportant. This is true, but for those who are concerned about naming, this code and following hold:
Mongo mongodb = new Mongo( "localhost", 27017 ); DB database = mongodb.getDB( "morphiaexample" ); Morphia morphia = new Morphia(); Datastore datastore = morphia.createDatastore( mongodb, "Scrooge" ); DBCollection collection = database.getCollection( "Peckerwoodarooney" ); ... public HotelDao( Morphia morphia, Mongo mongo ) { super( mongo, morphia, "Peckerwood" ); }
Nothing shows up (not database nor collection) until a hotel is created and persisted:
datastore.save( hotel );
...when the database, collection and document in that collection suddenly appear. The database name depends on what's passed to Morphia.createDatastore() and not, as you'd think, what's passed to mongodb.getDB(). The collection name is affected either by what you pass to the @Entity annotation on the POJO or the name of the POJO itself. What's passed to BasicDAO's constructor (superclass of HotelDao) is immaterial too.
@Entity( value="Scroogerooney" )
Here are the results of the above:
Every entity POJO must have a default, no-argument constructor or Morphia will croak with a message to the effect that there is no usable constructor, something like "No usable constructor for class").
That there is no such constructor may be inadvertant. By default it exists, but maybe you created a helpful constructor thereby removing the hidden default?
Here's the example from the web page coded up and very lightly enhanced to help explore issues.
package experiment.morphia; import org.bson.types.ObjectId; import com.google.code.morphia.annotations.Entity; import com.google.code.morphia.annotations.Id; @Entity public class Address { @Id private ObjectId id; private String street; private String city; private String state; private String zipcode; private String country; public ObjectId getId() { return this.id; } public void setId( ObjectId id ) { this.id = id; } public String getStreet() { return this.street; } public void setStreet( String street ) { this.street = street; } public String getCity() { return this.city; } public void setCity( String city ) { this.city = city; } public String getState() { return this.state; } public void setState( String state ) { this.state = state; } public String getZipcode() { return this.zipcode; } public void setZipcode( String zipcode ) { this.zipcode = zipcode; } public String getCountry() { return this.country; } public void setCountry( String country ) { this.country = country; } public String toString() { String string = ""; if( this.id != null ) string = "[" + this.id + "] "; string += this.street + " " + this.city + " "; if( this.state != null ) string += this.state + " "; string += this.country + " " + this.zipcode; return string; } }
package experiment.morphia; import org.bson.types.ObjectId; import com.google.code.morphia.annotations.Embedded; import com.google.code.morphia.annotations.Entity; import com.google.code.morphia.annotations.Id; @Entity public class Hotel { @Id private ObjectId id; private String name; private int stars; @Embedded private Address address; public ObjectId getId() { return id; } public void setId( ObjectId id ) { this.id = id; } public String getName() { return name; } public void setName( String name ) { this.name = name; } public int getStars() { return stars; } public void setStars( int stars ) { this.stars = stars; } public Address getAddress() { return address; } public void setAddress( Address address ) { this.address = address; } public String toString() { String string = "[" + this.id + "] " + this.name + " (" + this.stars + ")"; return string + ", " + this.address.toString(); } }
package experiment.morphia; import com.google.code.morphia.Morphia; import com.google.code.morphia.dao.BasicDAO; import com.mongodb.Mongo; public class HotelDao extends BasicDAO< Hotel, String > { public HotelDao( Morphia morphia, Mongo mongo ) { super( mongo, morphia, "hotels" ); } }
package experiment.morphia; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import com.google.code.morphia.Datastore; import com.google.code.morphia.Morphia; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.Mongo; import com.mongodb.MongoException; @SuppressWarnings( "unused" ) public class HotelMain { public static Logger log = Logger.getLogger( HotelMain.class ); private static Mongo mongodb; private static DB database; private static DBCollection collection; public static void main( String[] args ) { try { mongodb = new Mongo( "localhost", 27017 ); } catch( UnknownHostException e ) { log.error( "MongoDB host not found" ); } catch( MongoException e ) { log.error( "Error attempting MongoDB connection for hotels", e ); } database = mongodb.getDB( "morphiaexample" ); collection = database.getCollection( "hotels" ); Morphia morphia = null; Datastore datastore = null; morphia = new Morphia(); morphia.map( Hotel.class ).map( Address.class ); datastore = morphia.createDatastore( mongodb, "hotels" ); Hotel hotel = new Hotel(); hotel.setName( "Cockroach Haven" ); hotel.setStars( 4 ); Address address = new Address(); address.setStreet( "3222 South 525 West" ); address.setCity( "Bountiful" ); address.setState( "UT" ); address.setZipcode( "84010" ); address.setCountry( "US" ); // set address hotel.setAddress( address ); // save the POJO datastore.save( hotel ); // -------------------------------------------------------------------------- String hotelId = "1"; // the ID of the hotel we want to load // and then map it to our Hotel object hotel = datastore.get( Hotel.class, hotelId ); // Note: why is hotel now null? // -------------------------------------------------------------------------- // it is easy to get four-star hotels. List< Hotel > fourStarHotels; fourStarHotels = datastore.find( Hotel.class, "stars >=", 4 ).asList(); // or fourStarHotels = datastore.find( Hotel.class ).field( "stars" ).greaterThanOrEq( 4 ).asList(); for( Hotel h : fourStarHotels ) { System.out.println( h ); } } }
> use hotels switched to db hotels > show collections Hotel system.indexes > db.Hotels.find().forEach( printjson ); { "_id" : ObjectId("4fd61d105a378b649e6f3dff"), "className" : "experiment.morphia.Hotel", "name" : "Cockroach Haven", "stars" : 4, "address" : { "street" : "3222 South 525 West", "city" : "Bountiful", "state" : "UT", "zipcode" : "84010", "country" : "US" } }
Jun 11, 2012 10:31:21 AM com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory [4fd61d105a378b649e6f3dff] Cockroach Haven (4), 3222 South 525 West Bountiful UT US 84010
Here's the example augmented to demonstrate the case where Address becomes an embedded array of Address. Address itself doesn't change—you just use the code above.
package experiment.morphia; import java.util.ArrayList; import org.bson.types.ObjectId; import com.google.code.morphia.annotations.Embedded; import com.google.code.morphia.annotations.Entity; import com.google.code.morphia.annotations.Id; @Entity( noClassnameStored=true ) public class HotelChain { @Id private ObjectId id; private String name; private int stars; @Embedded private ArrayList< Address > addresses; public ObjectId getId() { return id; } public void setId( ObjectId id ) { this.id = id; } public String getName() { return name; } public void setName( String name ) { this.name = name; } public int getStars() { return stars; } public void setStars( int stars ) { this.stars = stars; } public ArrayList< Address > getAddresses() { return addresses; } public void setAddresses( ArrayList< Address > addresses ) { this.addresses = addresses; } }
package experiment.morphia; import com.google.code.morphia.Morphia; import com.google.code.morphia.dao.BasicDAO; import com.mongodb.Mongo; public class HotelChainDao extends BasicDAO< HotelChain, String > { public HotelChainDao( Morphia morphia, Mongo mongo ) { super( mongo, morphia, "hotelchains" ); } }
I did some inane stuff at the end of main() in order to inspect the results in the debugger and prove that the resulting POJO did indeed contain the array of addresses.
package experiment.morphia; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import com.google.code.morphia.Datastore; import com.google.code.morphia.Morphia; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.Mongo; import com.mongodb.MongoException; @SuppressWarnings( "unused" ) public class HotelChainMain { public static Logger log = Logger.getLogger( HotelChainMain.class ); private static Mongo mongodb; private static DB database; private static DBCollection collection; public static void main( String[] args ) { try { mongodb = new Mongo( "localhost", 27017 ); } catch( UnknownHostException e ) { log.error( "MongoDB host not found" ); } catch( MongoException e ) { log.error( "Error attempting MongoDB connection for hotel chains", e ); } database = mongodb.getDB( "morphiaexample" ); collection = database.getCollection( "hotels" ); Morphia morphia = null; Datastore datastore = null; morphia = new Morphia(); morphia.map( HotelChain.class ).map( Address.class ); datastore = morphia.createDatastore( mongodb, "hotelchains" ); HotelChain hotelchain = new HotelChain(); hotelchain.setName( "Hotel Hyatt" ); hotelchain.setStars( 4 ); ArrayList< Address > addresses = new ArrayList< Address >(); Address address = new Address(); address = new Address(); address.setStreet( "3222 South 525 West" ); address.setCity( "Bountiful" ); address.setState( "UT" ); address.setZipcode( "84101" ); address.setCountry( "US" ); addresses.add( address ); address = new Address(); address.setStreet( "59, rue Albert Premier" ); address.setCity( "Bezons" ); address.setZipcode( "95057" ); address.setCountry( "FR" ); addresses.add( address ); address = new Address(); address.setStreet( "Miquelallee Straß, 23" ); address.setCity( "Frankfurt" ); address.setZipcode( "65936" ); address.setCountry( "DE" ); addresses.add( address ); hotelchain.setAddresses( addresses ); // save the POJO datastore.save( hotelchain ); String hotelchainId = "1"; hotelchain = datastore.get( HotelChain.class, hotelchainId ); List< HotelChain > fourStarChains; fourStarChains = datastore.find( HotelChain.class ).field( "stars" ).greaterThanOrEq( 4 ).asList(); HotelChain h_c = null; for( HotelChain hc : fourStarChains ) { h_c = hc; System.out.println( hc ); } h_c.hashCode(); for( Address a : h_c.getAddresses() ) { System.out.println( a ); } } }
Beside the obvious concern of an embedded array, compare this output with the previous example to see that the @Entity( noClassnameStored=true ) annotation leads to no classname field in the document.
> show dbs hotelchains 0.203125GB hotels 0.203125GB > use hotelchains switched to db hotelchains > show collections HotelChain system.indexes > db.HotelChain.find().forEach( printjson ); { "_id" : ObjectId("4fd61bfb5a37047b69774828"), "name" : "Hotel Hyatt", "stars" : 4, "addresses" : [ { "street" : "3222 South 525 West", "city" : "Bountiful", "state" : "UT", "zipcode" : "84101", "country" : "US" }, { "street" : "59, rue Albert Premier", "city" : "Bezons", "zipcode" : "95057", "country" : "FR" }, { "street" : "Miquelallee Straß, 23", "city" : "Frankfurt", "zipcode" : "65936", "country" : "DE" } ] }
Jun 11, 2012 10:25:31 AM com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory experiment.morphia.HotelChain@5ff06dc3 3222 South 525 West Bountiful UT US 84101 59, rue Albert Premier Bezons FR 95057 Miquelallee Straß, 23 Frankfurt DE 65936