#MongoBostonMorphia: SimplifyingPersistence for Java andMongoDBJeff YeminEngineering Manager, 10gen
MongoDB on the JVM• MongoDB Java Driver  – Map-based API• JVM language integrations  – Casbah (Scala)  – Jmongo (Ruby)  – ...
Morphia• Object Document Mapper  – Specifed with annotations  – Implemented with reflection• Fluent query and update APIs ...
Morphia by Example• Model• Test• Output
Dependencies<dependency>  <groupId>org.mongodb</groupId>  <artifactId>mongo-java-driver</artifactId>  <version>2.8.0</vers...
Repository<repository>  <id>morphia</id>  <name>Morphia</name>  <url>http://morphia.googlecode.com/svn/mavenrepo/</url>  <...
Create the DatastoreMorphia morphia = new Morphia();Mongo mongo = new Mongo();Datastore ds = morphia.createDatastore(mongo...
Entity Modelling
Lets model github
First Entity (model)class Programmer {   String name;}
First Entity (test)Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";ds.save(programmer);
First Entity (shell)> db.Programmer.findOne(){    "_id" : ObjectId("503292d51aa814c051554696"),    "className" : "demo.Pro...
@Id (model)class Programmer {   @Id ObjectId id;   String name;   public void toString() {…}}
@Id (test)Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";ds.save(programmer);System.out.print...
@Id (toString)Programmer{id=5032935f1aa8a8aa3485b441,      name=Scott Hernandez}
String Id (model)class Programmer {   @Id String githubUserName;   String name;}
String Id (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name= "Sc...
String Id (shell)> db.Programmer.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    "name" : "...
@Entity (model)@Entity("programmers")class Programmer {   @Id String githubUserName;   String name;}
@Entity (shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    "name" : "S...
More primitives (model)@Entity("programmers")class Programmer {   @Id String githubUserName;   String name;   Date memberS...
More primitives (test)Programmer scott = new Programmer();scott.userName = "scotthernandez";scott.name = "Scott Hernandez"...
More primitives (shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    "na...
Primitive Array (Model)@Entity("programmers")class Programmer {   @Id String githubUserName;   String name;   Date memberS...
Primitive Array (test)Programmer scott = new Programmer();scott.userName = "scotthernandez";scott.name = "Scott Hernandez"...
Primitive Array (shell) db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    "nam...
@Embedded (model)@Entity("programmers")class Programmer {   @Id String githubUserName;   Name name;   Date memberSince;   ...
@Embedded (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = ne...
@Embedded (shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    "name" : ...
@Embedded List (model)@Entity("programmers")class Programmer {   @Id String githubUserName;   Name name;   Date memberSinc...
@Embedded (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = ne...
@Embedded List (shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    …   ...
@Reference (model)@Entity("repos")class Repository {   @Id ObjectId id;   @Reference Programmer owner;   String name;   St...
@Reference (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = n...
@Reference (shell)> db.repos.findOne(){    "_id" : ObjectId("503297e31aa8255abe542aaa"),    "className" : "demo.Repository...
Small schema change (model)abstract class Member {  @Id String userName;  @Property("memberSince") Date since;  boolean ac...
Small schema change (test)Programmer scott = new Programmer();//…ds.save(scott);// save mongodb OrganizationOrganization m...
Small schema change (shell)> db.orgs.findOne(){    "_id" : "mongodb",    "className" : "demo.Organization",    "memberSinc...
Small schema change (shell, 2)> db.repos.find().toArray()[    {        "_id" : ObjectId("503298be1aa8b1d255e5d45b"),      ...
Querying
Find by Equality (test)•   ds.get(Programmer.class, "scotthernandez")•   ds.find(Programmer.class, "userName", "scottherna...
Find by Equality (logs)•   test.programmers query: { _id: "scotthernandez" }•   test.programmers query: { userName: "scott...
Find by Range (test)•   ds.find(Programmer.class).field("followers").greaterThan(0)•   ds.find(Programmer.class).filter("f...
Find by Range (logs)•   test.programmers query: { followers: { $gt: 0 } }•   test.programmers query: { followers: { $gt: 0...
Combining conditions (test)ds.find(Programmer.class).    field("since").lessThan(dateFmt.parse("Jan 1, 2010")).    field("...
Combining conditions (logs)test.programmers query: {  memberSince: { $lt: new Date(1262322000000) },  followers: { $gt: 0 }}
Find by Reference                            (test)Programmer scott = new Programmer("scotthernandez")ds.find(Repository.c...
Find by Reference (logs)test.repos query: {  owner: { $ref: "programmers", $id: "scotthernandez" }}
Indexing
@Indexed• Annotation for fields   –   value (IndexDirection)   –   name (String)   –   unique (boolean)   –   dropDups (bo...
@Indexes and @Index• @Indexes: Annotation for types  – value (Index[])• @Index  – value (String)  – Others same as @Indexe...
Updating
Updating with save (test)Programmer jeff = createJeff();ds.save(jeff);// jeff is following scott, so increment// scotts fo...
Updating with save (logs)update test.programmersquery: {  _id: "scotthernandez",}update: {  _id: "scotthernandez",  classN...
Updating with save (shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer",    ...
Optimistic Concurrency (model)@Entitypublic abstract class Member {  @Id String userName;  @Property("memberSince") Date s...
Optimistic Concurrency (logs)update test.programmersquery: {   _id: "scotthernandez",   version: 1345497713173 }update: { ...
Optimistic Concurrency(shell)> db.programmers.findOne(){    "_id" : "scotthernandez",    "className" : "demo.Programmer", ...
UpdateOperations (test)Programmer jeff = createJeff();ds.save(jeff);// increment followers of scott by oneUpdateOperations...
UpdateOperations (logs)update test.programmersquery: {  _id: "scotthernandez"}update: {  $inc: { followers: 1 }}
Web Resources• Morphia home: http://code.google.com/p/morphia/• Morphia user group:  https://groups.google.com/forum/?from...
Thanks!• Jeff Yemin   – https://twitter.com/@jeffyemin   – jeff.yemin@10gen.com   – https://github.com/jyemin/
#MongoBostonThank YouJeff YeminEngineering Manager, 10gen
Upcoming SlideShare
Loading in …5
×

Simplifying Persistence for Java and MongoDB with Morphia

7,739 views

Published on

Interested in learning more about MongoDB? Sign up for MongoSV, the largest annual user conference dedicated to MongoDB. Learn more at MongoSV.com

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,739
On SlideShare
0
From Embeds
0
Number of Embeds
712
Actions
Shares
0
Downloads
71
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide
  • Builds on the java driver&quot;test&quot; is the name of a database&apos;
  • NameEmilMember SinceFollowersRespositories
  • No annotations. Pure POJO
  • 1. Save will insert or update
  • Collection name defaults to class name_id is generated as an ObjectIdclassName has the full class name, including package. Used for polymorphic collectionCan you query for base class? How?
  • 1. Morphia will generate an id and stuff it in the field annotated with @Id
  • 1. If you already have a unique id, you should use it as your @Id
  • 1. Morphia won&apos;t generate these for you
  • 1. If you just use @Entity, it defaults the collection name to the class name.
  • Note the collection name
  • Let&apos;s switch it up. Instead of embedding the repos in the programmer, let&apos;s have repos as top-level docs that reference owner by key
  • Get by primary keyShortcut for getting by a single propertyLongcut, same as above but extensible
  • 1. Note the weird syntax to make followers descending
  • Note that to update followers, we updated everything…Point out the problems with this
  • Simplifying Persistence for Java and MongoDB with Morphia

    1. 1. #MongoBostonMorphia: SimplifyingPersistence for Java andMongoDBJeff YeminEngineering Manager, 10gen
    2. 2. MongoDB on the JVM• MongoDB Java Driver – Map-based API• JVM language integrations – Casbah (Scala) – Jmongo (Ruby) – Monger (Clojure)• ODM (Object Document Mapper) – Morphia – Spring Data MongoDB
    3. 3. Morphia• Object Document Mapper – Specifed with annotations – Implemented with reflection• Fluent query and update APIs – Runtime validation
    4. 4. Morphia by Example• Model• Test• Output
    5. 5. Dependencies<dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.8.0</version></dependency><dependency> <groupId>com.google.code.morphia</groupId> <artifactId>morphia</artifactId> <version>0.99</version></dependency>
    6. 6. Repository<repository> <id>morphia</id> <name>Morphia</name> <url>http://morphia.googlecode.com/svn/mavenrepo/</url> <layout>default</layout></repository>
    7. 7. Create the DatastoreMorphia morphia = new Morphia();Mongo mongo = new Mongo();Datastore ds = morphia.createDatastore(mongo, "test");
    8. 8. Entity Modelling
    9. 9. Lets model github
    10. 10. First Entity (model)class Programmer { String name;}
    11. 11. First Entity (test)Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";ds.save(programmer);
    12. 12. First Entity (shell)> db.Programmer.findOne(){ "_id" : ObjectId("503292d51aa814c051554696"), "className" : "demo.Programmer", "name" : "Scott Hernandez"}
    13. 13. @Id (model)class Programmer { @Id ObjectId id; String name; public void toString() {…}}
    14. 14. @Id (test)Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";ds.save(programmer);System.out.println(programmer)
    15. 15. @Id (toString)Programmer{id=5032935f1aa8a8aa3485b441, name=Scott Hernandez}
    16. 16. String Id (model)class Programmer { @Id String githubUserName; String name;}
    17. 17. String Id (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name= "Scott Hernandez";ds.save(programmer);
    18. 18. String Id (shell)> db.Programmer.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez"}
    19. 19. @Entity (model)@Entity("programmers")class Programmer { @Id String githubUserName; String name;}
    20. 20. @Entity (shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez"}
    21. 21. More primitives (model)@Entity("programmers")class Programmer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers;}
    22. 22. More primitives (test)Programmer scott = new Programmer();scott.userName = "scotthernandez";scott.name = "Scott Hernandez";scott.since = dateFmt.parse("Aug 12, 2009");scott.active = true;scott.followers = 8;ds.save(scott);
    23. 23. More primitives (shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez", "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "followers" : 8}
    24. 24. Primitive Array (Model)@Entity("programmers")class Programmer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers; List<String> following;}
    25. 25. Primitive Array (test)Programmer scott = new Programmer();scott.userName = "scotthernandez";scott.name = "Scott Hernandez";scott.since = dateFmt.parse("Aug 12, 2009");scott.active = true;scott.followers = 8;scott.following = Arrays.asList("moraes", "stickfigure");ds.save(scott);
    26. 26. Primitive Array (shell) db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez", "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "followers" : 8, "following" : [ "moraes", "stickfigure" ]}
    27. 27. @Embedded (model)@Entity("programmers")class Programmer { @Id String githubUserName; Name name; Date memberSince; boolean active; int followers; List<String> following;}@Embeddedclass Name { String first, last;}
    28. 28. @Embedded (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = new Name("Scott", "Hernandez");programmer.memberSince = dateFmt.parse("Aug 12, 2009");programmer.active = true;programmer.followers = 8;programmer.following = Arrays.asList("moraes", "stickfigure");ds.save(programmer);
    29. 29. @Embedded (shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : { "first" : "Scott", "last" : "Hernandez" }, "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "followers" : 8, "following" : [ "moraes", "stickfigure" ]}
    30. 30. @Embedded List (model)@Entity("programmers")class Programmer { @Id String githubUserName; Name name; Date memberSince; boolean active; int followers; List<String> following; List<Repository> repositories;}@Embeddedclass Name { String first, last;}@Embeddedclass Repository { String name; String forkedFrom;}
    31. 31. @Embedded (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = new Name("Scott", "Hernandez");programmer.memberSince = dateFmt.parse("Aug 12, 2009");programmer.active = true;programmer.followers = 8;programmer.following = Arrays.asList("moraes", "stickfigure");programmer.repositories = Arrays.asList( new Repository("docs", "mongodb/docs"), new Repository("mongo-java-driver", "mongodb/mongo-java-driver"));ds.save(programmer);
    32. 32. @Embedded List (shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", … "repositories" : [ { "name" : "docs", "forkedFrom" : "mongodb/docs" }, { "name" : "mongo-java-driver", "forkedFrom" : "mongodb/mongo-java-driver" } ]}
    33. 33. @Reference (model)@Entity("repos")class Repository { @Id ObjectId id; @Reference Programmer owner; String name; String forkedFrom;}
    34. 34. @Reference (test)Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name = new Name("Scott", "Hernandez");programmer.memberSince = dateFmt.parse("Aug 12, 2009");programmer.active = true;programmer.followers = 8;programmer.following = Arrays.asList("moraes", "stickfigure");ds.save(programmer);Repository repo = new Repository(programmer, "docs", "mongodb/docs");ds.save(repo);
    35. 35. @Reference (shell)> db.repos.findOne(){ "_id" : ObjectId("503297e31aa8255abe542aaa"), "className" : "demo.Repository", "owner" : DBRef("programmers", "scotthernandez"), "name" : "docs", "forkedFrom" : "mongodb/docs"}
    36. 36. Small schema change (model)abstract class Member { @Id String userName; @Property("memberSince") Date since; boolean active; String name;}@Entity("programmers")class Programmer extends Member { int followers; List<String> following;}@Entity("orgs")class Organization extends Member {}@Entity("repos")class Repository { @Id ObjectId id; @Reference Member owner; String name; @Reference(lazy=true) Repository forkedFrom;}
    37. 37. Small schema change (test)Programmer scott = new Programmer();//…ds.save(scott);// save mongodb OrganizationOrganization mongodb = new Organization("mongodb", "mongodb", sdf.parse("Jan 8, 2009"));ds.save(mongodb);// save mongodbs docs RepositoryRepository mongoDocs = new Repository(mongodb, "docs");ds.save(mongoDocs);// save Scotts forked docs RepositoryRepository scottDocs = new Repository(scott, "docs", mongoDocs);ds.save(scottDocs);
    38. 38. Small schema change (shell)> db.orgs.findOne(){ "_id" : "mongodb", "className" : "demo.Organization", "memberSince" : ISODate("2009-01-08T05:00:00Z"), "active" : false, "name" : "mongodb"}> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "name" : "Scott Hernandez" …}
    39. 39. Small schema change (shell, 2)> db.repos.find().toArray()[ { "_id" : ObjectId("503298be1aa8b1d255e5d45b"), "className" : "demo.Repository", "owner" : DBRef("orgs", "mongodb"), "name" : "docs" }, { "_id" : ObjectId("503298be1aa8b1d255e5d45c"), "className" : "demo.Repository", "owner" : DBRef("programmers", "scotthernandez"), "name" : "docs", "forkedFrom" : DBRef("repos", ObjectId("503298be1aa8b1d255e5d45b")) }]
    40. 40. Querying
    41. 41. Find by Equality (test)• ds.get(Programmer.class, "scotthernandez")• ds.find(Programmer.class, "userName", "scotthernandez")• ds.find(Programmer.class).field("userName").equal("scotthernandez”)
    42. 42. Find by Equality (logs)• test.programmers query: { _id: "scotthernandez" }• test.programmers query: { userName: "scotthernandez" }• test.programmers query: { userName: "scotthernandez" }
    43. 43. Find by Range (test)• ds.find(Programmer.class).field("followers").greaterThan(0)• ds.find(Programmer.class).filter("followers >", 0)• ds.find(Programmer.class).field("since"). lessThan(sdf.parse("Jan 1, 2010"))
    44. 44. Find by Range (logs)• test.programmers query: { followers: { $gt: 0 } }• test.programmers query: { followers: { $gt: 0 } }• test.programmers query: { memberSince: { $lt: new Date(1262322000000) } }
    45. 45. Combining conditions (test)ds.find(Programmer.class). field("since").lessThan(dateFmt.parse("Jan 1, 2010")). field("followers").greaterThan(0)
    46. 46. Combining conditions (logs)test.programmers query: { memberSince: { $lt: new Date(1262322000000) }, followers: { $gt: 0 }}
    47. 47. Find by Reference (test)Programmer scott = new Programmer("scotthernandez")ds.find(Repository.class).field("owner").equal(scott)
    48. 48. Find by Reference (logs)test.repos query: { owner: { $ref: "programmers", $id: "scotthernandez" }}
    49. 49. Indexing
    50. 50. @Indexed• Annotation for fields – value (IndexDirection) – name (String) – unique (boolean) – dropDups (boolean) – background (boolean) – sparse (boolean)• Examples – @Indexed(value=IndexDirection.ASC, name="followers") int followers; – @Indexed @Reference(lazy = true) Repository forkedFrom;
    51. 51. @Indexes and @Index• @Indexes: Annotation for types – value (Index[])• @Index – value (String) – Others same as @Indexed• Examples – @Indexes(@Index("since, -followers")) public class Programmer {…}
    52. 52. Updating
    53. 53. Updating with save (test)Programmer jeff = createJeff();ds.save(jeff);// jeff is following scott, so increment// scotts followers and re-saveProgrammer scott = ds.get(Programmer.class, "scotthernandez")scott.followers++;ds.save(scott);
    54. 54. Updating with save (logs)update test.programmersquery: { _id: "scotthernandez",}update: { _id: "scotthernandez", className: "demo.Programmer", followers: 9, following: [ "moraes", "stickfigure" ], memberSince: new Date(1250049600000), active: true, name: "Scott Hernandez",}
    55. 55. Updating with save (shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "followers" : 9, "following" : [ "moraes", "stickfigure" ], "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "name" : "Scott Hernandez"}
    56. 56. Optimistic Concurrency (model)@Entitypublic abstract class Member { @Id String userName; @Property("memberSince") Date since; boolean active; String name; @Version Long version;}
    57. 57. Optimistic Concurrency (logs)update test.programmersquery: { _id: "scotthernandez", version: 1345497713173 }update: { _id: "scotthernandez", className: "demo.Programmer", followers: 9, following: [ "moraes", "stickfigure" ], memberSince: new Date(1250049600000), active: true, name: "Scott Hernandez", version: 1345497718181}
    58. 58. Optimistic Concurrency(shell)> db.programmers.findOne(){ "_id" : "scotthernandez", "className" : "demo.Programmer", "followers" : 9, "following" : [ "moraes", "stickfigure" ], "memberSince" : ISODate("2009-08-12T04:00:00Z"), "active" : true, "name" : "Scott Hernandez", "version" : NumberLong("1345497718181")}
    59. 59. UpdateOperations (test)Programmer jeff = createJeff();ds.save(jeff);// increment followers of scott by oneUpdateOperations<Programmer> incrementFollowing = ds.createUpdateOperations(Programmer.class). inc("followers", 1);Query<Programmer> queryForScott = ds.find(Programmer.class, "userName", "scotthernandez");ds.update(queryForScott, incrementFollowing);
    60. 60. UpdateOperations (logs)update test.programmersquery: { _id: "scotthernandez"}update: { $inc: { followers: 1 }}
    61. 61. Web Resources• Morphia home: http://code.google.com/p/morphia/• Morphia user group: https://groups.google.com/forum/?fromgroups#!forum/morphia• Demo code: https://github.com/jyemin/morphia-demo – Separate commit and tag for each slide, so you can play along
    62. 62. Thanks!• Jeff Yemin – https://twitter.com/@jeffyemin – jeff.yemin@10gen.com – https://github.com/jyemin/
    63. 63. #MongoBostonThank YouJeff YeminEngineering Manager, 10gen

    ×