Morphia: Simplifying
Persistence for Java and
MongoDB
Jeff Yemin
Java Evangelist, 10gen
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
Morphia
• Object Document Mapper
  – Specified with annotations
  – Implemented with reflection

• Fluent query and update APIs
  – Runtime validation
Morphia by Example
• Model
• Test
• Output
Dependencies
<dependency>
  <groupId>org.mongodb</groupId>
  <artifactId>mongo-java-driver</artifactId>
  <version>2.10.1</version>
</dependency>

<dependency>
  <groupId>com.google.code.morphia</groupId>
  <artifactId>morphia</artifactId>
  <version>0.99</version>
</dependency>
Repository
<repository>
  <id>morphia</id>
  <name>Morphia</name>
  <url>http://morphia.googlecode.com/svn/mavenrepo/</url>
  <layout>default</layout>
</repository>
Create the Datastore
Morphia morphia = new Morphia();
Mongo mongo = new Mongo();
Datastore ds = morphia.createDatastore(mongo, "test");
Entity Modelling
Let's 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.Programmer",
    "name" : "Scott Hernandez"
}
@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.println(programmer)
@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= "Scott Hernandez";

ds.save(programmer);
String Id (shell)
> db.Programmer.findOne()
{
    "_id" : "scotthernandez",
    "className" : "demo.Programmer",
    "name" : "Scott Hernandez"
}
@Entity (model)
@Entity("programmers")
class Programmer {
   @Id String githubUserName;
   String name;
}
@Entity (shell)
> db.programmers.findOne()
{
    "_id" : "scotthernandez",
    "className" : "demo.Programmer",
    "name" : "Scott Hernandez"
}
More primitives (model)
@Entity("programmers")
class Programmer {
   @Id String githubUserName;
   String name;
   Date memberSince;
   boolean active;
   int followers;
}
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);
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
}
Primitive Array (Model)
@Entity("programmers")
class Programmer {
   @Id String githubUserName;
   String name;
   Date memberSince;
   boolean active;
   int followers;
   List<String> following;
}
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);
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"
    ]
}
@Embedded (model)
@Entity("programmers")
class Programmer {
   @Id String githubUserName;
   Name name;
   Date memberSince;
   boolean active;
   int followers;
   List<String> following;
}

@Embedded
class Name {
   String first, last;
}
@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);
@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"
    ]
}
@Embedded List (model)
@Entity("programmers")
class Programmer {
   @Id String githubUserName;
   Name name;
   Date memberSince;
   boolean active;
   int followers;
   List<String> following;
   List<Repository> repositories;
}
@Embedded
class Name {
   String first, last;
}
@Embedded
class Repository {
   String name;
   String forkedFrom;
}
@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);
@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"
         }
    ]
}
@Reference (model)
@Entity("repos")
class Repository {
   @Id ObjectId id;
   @Reference Programmer owner;
   String name;
   String forkedFrom;
}
@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);
@Reference (shell)
> db.repos.findOne()
{
    "_id" : ObjectId("503297e31aa8255abe542aaa"),
    "className" : "demo.Repository",
    "owner" : DBRef("programmers", "scotthernandez"),
    "name" : "docs",
    "forkedFrom" : "mongodb/docs"
}
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;
}
Small schema change (test)
Programmer scott = new Programmer();
//…
ds.save(scott);

// save mongodb Organization
Organization mongodb = new Organization("mongodb",
       "mongodb", sdf.parse("Jan 8, 2009"));
ds.save(mongodb);

// save mongodb's docs Repository
Repository mongoDocs = new Repository(mongodb, "docs");
ds.save(mongoDocs);

// save Scott's forked docs Repository
Repository scottDocs = new Repository(scott, "docs",
                          mongoDocs);
ds.save(scottDocs);
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"
      …
}
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"))
    }
]
Querying
Find by Equality (test)
•   ds.get(Programmer.class, "scotthernandez")

•   ds.find(Programmer.class, "name", "Scott Hernandez")

•   ds.find(Programmer.class).field("name").equal("Scott Hernandez”)
Find by Equality (logs)
•   test.programmers query: { _id: "scotthernandez" }

•   test.programmers query: { name: "Scott Hernandez" }

•   test.programmers query: { name: "Scott Hernandez" }
Find by Range (test)
•   ds.find(Programmer.class).field("followers").greaterThan(0)

•   ds.find(Programmer.class).filter("followers >", 0)

•   ds.find(Programmer.class).field("memberSince").lessThan(sdf.parse("Jan 1, 2010"))
Find by Range (logs)
•   test.programmers query: { followers: { $gt: 0 } }

•   test.programmers query: { followers: { $gt: 0 } }

•   test.programmers query: { memberSince: { $lt: new Date(1262322000000) } }
Combining conditions (test)
ds.find(Programmer.class).
    field("memberSince").lessThan(dateFmt.parse("Jan 1, 2010")).
     field("followers").greaterThan(0)
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.class).field("owner").equal(scott)
Find by Reference (logs)
test.repos query: {
  owner: { $ref: "programmers", $id: "scotthernandez" }
}
Indexing
@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 Repository forkedFrom;
@Indexes and @Index
• @Indexes: Annotation for types
  – value (Index[])

• @Index
  – value (String)
  – Others same as @Indexed

• Examples
  – @Indexes(@Index("since, -followers")) public class
    Programmer {…}
Updating
Updating with save (test)
Programmer jeff = createJeff();
ds.save(jeff);

// jeff is following scott, so increment
// scott's followers and re-save
Programmer scott = ds.get(Programmer.class,
                    "scotthernandez")

scott.followers++;
ds.save(scott);
Updating with save (logs)
update test.programmers

query: {
  _id: "scotthernandez",
}
update: {
  _id: "scotthernandez",
  className: "demo.Programmer",
  followers: 9,
  following: [ "moraes", "stickfigure" ],
  memberSince: new Date(1250049600000),
  active: true,
  name: "Scott Hernandez",
}
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"
}
Optimistic Concurrency (model)
@Entity
public abstract class Member {
  @Id String userName;
  @Property("memberSince") Date since;
  boolean active;
  String name;
  @Version Long version;
}
Optimistic Concurrency (logs)
update test.programmers

query: {
   _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
}
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")
}
UpdateOperations (test)
Programmer jeff = createJeff();
ds.save(jeff);

// increment followers of scott by one
UpdateOperations<Programmer> incrementFollowing =
 ds.createUpdateOperations(Programmer.class).
         inc("followers", 1);


Query<Programmer> queryForScott =
 ds.find(Programmer.class, "_id", "scotthernandez");


ds.update(queryForScott, incrementFollowing);
UpdateOperations (logs)
update test.programmers

query: {
  _id: "scotthernandez"
}

update: {
  $inc: { followers: 1 }
}
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
Thanks!
• Jeff Yemin
   – https://twitter.com/@jeffyemin
   – jeff.yemin@10gen.com
   – https://github.com/jyemin/
Thank You
Jeff Yemin
Engineering Manager, 10gen

Webinar: Simplifying Persistence for Java and MongoDB

  • 1.
    Morphia: Simplifying Persistence forJava and MongoDB Jeff Yemin Java Evangelist, 10gen
  • 2.
    MongoDB on theJVM • MongoDB Java Driver – Map-based API • JVM language integrations – Casbah (Scala) – Jmongo (Ruby) – Monger (Clojure) • ODM (Object Document Mapper) – Morphia – Spring Data MongoDB
  • 3.
    Morphia • Object DocumentMapper – Specified with annotations – Implemented with reflection • Fluent query and update APIs – Runtime validation
  • 4.
    Morphia by Example •Model • Test • Output
  • 5.
    Dependencies <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.10.1</version> </dependency> <dependency> <groupId>com.google.code.morphia</groupId> <artifactId>morphia</artifactId> <version>0.99</version> </dependency>
  • 6.
    Repository <repository> <id>morphia</id> <name>Morphia</name> <url>http://morphia.googlecode.com/svn/mavenrepo/</url> <layout>default</layout> </repository>
  • 7.
    Create the Datastore Morphiamorphia = new Morphia(); Mongo mongo = new Mongo(); Datastore ds = morphia.createDatastore(mongo, "test");
  • 8.
  • 9.
  • 10.
    First Entity (model) classProgrammer { String name; }
  • 11.
    First Entity (test) Programmerprogrammer = new Programmer(); programmer.name= "Scott Hernandez"; ds.save(programmer);
  • 12.
    First Entity (shell) >db.Programmer.findOne() { "_id" : ObjectId("503292d51aa814c051554696"), "className" : "demo.Programmer", "name" : "Scott Hernandez" }
  • 13.
    @Id (model) class Programmer{ @Id ObjectId id; String name; public void toString() {…} }
  • 14.
    @Id (test) Programmer programmer= new Programmer(); programmer.name= "Scott Hernandez"; ds.save(programmer); System.out.println(programmer)
  • 15.
  • 16.
    String Id (model) classProgrammer { @Id String githubUserName; String name; }
  • 17.
    String Id (test) Programmerprogrammer = new Programmer(); programmer.githubUserName = "scotthernandez"; programmer.name= "Scott Hernandez"; ds.save(programmer);
  • 18.
    String Id (shell) >db.Programmer.findOne() { "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez" }
  • 19.
    @Entity (model) @Entity("programmers") class Programmer{ @Id String githubUserName; String name; }
  • 20.
    @Entity (shell) > db.programmers.findOne() { "_id" : "scotthernandez", "className" : "demo.Programmer", "name" : "Scott Hernandez" }
  • 21.
    More primitives (model) @Entity("programmers") classProgrammer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers; }
  • 22.
    More primitives (test) Programmerscott = 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.
    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.
    Primitive Array (Model) @Entity("programmers") classProgrammer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers; List<String> following; }
  • 25.
    Primitive Array (test) Programmerscott = 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.
    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.
    @Embedded (model) @Entity("programmers") class Programmer{ @Id String githubUserName; Name name; Date memberSince; boolean active; int followers; List<String> following; } @Embedded class Name { String first, last; }
  • 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.
    @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.
    @Embedded List (model) @Entity("programmers") classProgrammer { @Id String githubUserName; Name name; Date memberSince; boolean active; int followers; List<String> following; List<Repository> repositories; } @Embedded class Name { String first, last; } @Embedded class Repository { String name; String forkedFrom; }
  • 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.
    @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.
    @Reference (model) @Entity("repos") class Repository{ @Id ObjectId id; @Reference Programmer owner; String name; String forkedFrom; }
  • 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.
    @Reference (shell) > db.repos.findOne() { "_id" : ObjectId("503297e31aa8255abe542aaa"), "className" : "demo.Repository", "owner" : DBRef("programmers", "scotthernandez"), "name" : "docs", "forkedFrom" : "mongodb/docs" }
  • 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.
    Small schema change(test) Programmer scott = new Programmer(); //… ds.save(scott); // save mongodb Organization Organization mongodb = new Organization("mongodb", "mongodb", sdf.parse("Jan 8, 2009")); ds.save(mongodb); // save mongodb's docs Repository Repository mongoDocs = new Repository(mongodb, "docs"); ds.save(mongoDocs); // save Scott's forked docs Repository Repository scottDocs = new Repository(scott, "docs", mongoDocs); ds.save(scottDocs);
  • 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.
    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.
  • 41.
    Find by Equality(test) • ds.get(Programmer.class, "scotthernandez") • ds.find(Programmer.class, "name", "Scott Hernandez") • ds.find(Programmer.class).field("name").equal("Scott Hernandez”)
  • 42.
    Find by Equality(logs) • test.programmers query: { _id: "scotthernandez" } • test.programmers query: { name: "Scott Hernandez" } • test.programmers query: { name: "Scott Hernandez" }
  • 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("memberSince").lessThan(sdf.parse("Jan 1, 2010"))
  • 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.
    Combining conditions (test) ds.find(Programmer.class). field("memberSince").lessThan(dateFmt.parse("Jan 1, 2010")). field("followers").greaterThan(0)
  • 46.
    Combining conditions (logs) test.programmersquery: { memberSince: { $lt: new Date(1262322000000) }, followers: { $gt: 0 } }
  • 47.
    Find by Reference (test) Programmer scott = new Programmer("scotthernandez") ds.find(Repository.class).field("owner").equal(scott)
  • 48.
    Find by Reference(logs) test.repos query: { owner: { $ref: "programmers", $id: "scotthernandez" } }
  • 49.
  • 50.
    @Indexed • Annotation forfields – value (IndexDirection) – name (String) – unique (boolean) – dropDups (boolean) – background (boolean) – sparse (boolean) • Examples – @Indexed(value=IndexDirection.ASC, name="followers") int followers; – @Indexed @Reference Repository forkedFrom;
  • 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.
  • 53.
    Updating with save(test) Programmer jeff = createJeff(); ds.save(jeff); // jeff is following scott, so increment // scott's followers and re-save Programmer scott = ds.get(Programmer.class, "scotthernandez") scott.followers++; ds.save(scott);
  • 54.
    Updating with save(logs) update test.programmers query: { _id: "scotthernandez", } update: { _id: "scotthernandez", className: "demo.Programmer", followers: 9, following: [ "moraes", "stickfigure" ], memberSince: new Date(1250049600000), active: true, name: "Scott Hernandez", }
  • 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.
    Optimistic Concurrency (model) @Entity publicabstract class Member { @Id String userName; @Property("memberSince") Date since; boolean active; String name; @Version Long version; }
  • 57.
    Optimistic Concurrency (logs) updatetest.programmers query: { _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.
    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.
    UpdateOperations (test) Programmer jeff= createJeff(); ds.save(jeff); // increment followers of scott by one UpdateOperations<Programmer> incrementFollowing = ds.createUpdateOperations(Programmer.class). inc("followers", 1); Query<Programmer> queryForScott = ds.find(Programmer.class, "_id", "scotthernandez"); ds.update(queryForScott, incrementFollowing);
  • 60.
    UpdateOperations (logs) update test.programmers query:{ _id: "scotthernandez" } update: { $inc: { followers: 1 } }
  • 61.
    Web Resources • Morphiahome: 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.
    Thanks! • Jeff Yemin – https://twitter.com/@jeffyemin – jeff.yemin@10gen.com – https://github.com/jyemin/
  • 63.

Editor's Notes

  • #8 Builds on the java driver&quot;test&quot; is the name of a database&apos;
  • #10 NameEmilMember SinceFollowersRespositories
  • #11 No annotations. Pure POJO
  • #12 1. Save will insert or update
  • #13 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?
  • #16 1. Morphia will generate an id and stuff it in the field annotated with @Id
  • #17 1. If you already have a unique id, you should use it as your @Id
  • #18 1. Morphia won&apos;t generate these for you
  • #20 1. If you just use @Entity, it defaults the collection name to the class name.
  • #21 Note the collection name
  • #34 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
  • #42 Get by primary keyShortcut for getting by a single propertyLongcut, same as above but extensible
  • #52 1. Note the weird syntax to make followers descending
  • #55 Note that to update followers, we updated everything…Point out the problems with this