simplifying persistence for java and mongodb with morphia

Post on 25-May-2015

4.753 Views

Category:

Documents

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Engineering Manager, 10gen

Jeff Yemin

#MongoBoston

Morphia: Simplifying Persistence for Java and MongoDB

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– Specifed with annotations– Implemented with reflection

• Fluent query and update APIs– Runtime validation

Morphia by Example

• Model

• Test

• Output

<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>

Dependencies

<repository> <id>morphia</id> <name>Morphia</name> <url>http://morphia.googlecode.com/svn/mavenrepo/</url> <layout>default</layout></repository>

Repository

Morphia morphia = new Morphia();Mongo mongo = new Mongo();Datastore ds = morphia.createDatastore(mongo, "test");

Create the Datastore

Entity Modelling

Let's model github

class Programmer { String name;}

First Entity (model)

Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";

ds.save(programmer);

First Entity (test)

> db.Programmer.findOne(){

"_id" : ObjectId("503292d51aa814c051554696"),"className" : "demo.Programmer","name" : "Scott Hernandez"

}

First Entity (shell)

class Programmer { @Id ObjectId id; String name; public void toString() {…}}

@Id (model)

Programmer programmer = new Programmer();programmer.name= "Scott Hernandez";

ds.save(programmer);System.out.println(programmer)

@Id (test)

Programmer{id=5032935f1aa8a8aa3485b441, name='Scott Hernandez'}

@Id (toString)

class Programmer { @Id String githubUserName; String name;}

String Id (model)

Programmer programmer = new Programmer();programmer.githubUserName = "scotthernandez";programmer.name= "Scott Hernandez";

ds.save(programmer);

String Id (test)

> db.Programmer.findOne(){

"_id" : "scotthernandez","className" : "demo.Programmer","name" : "Scott Hernandez"

}

String Id (shell)

@Entity("programmers")class Programmer { @Id String githubUserName; String name;}

@Entity (model)

> db.programmers.findOne(){

"_id" : "scotthernandez","className" : "demo.Programmer","name" : "Scott Hernandez"

}

@Entity (shell)

@Entity("programmers")class Programmer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers;}

More primitives (model)

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 (test)

> db.programmers.findOne(){

"_id" : "scotthernandez","className" : "demo.Programmer","name" : "Scott Hernandez","memberSince" : ISODate("2009-08-12T04:00:00Z"),"active" : true,"followers" : 8

}

More primitives (shell)

@Entity("programmers")class Programmer { @Id String githubUserName; String name; Date memberSince; boolean active; int followers; List<String> following;}

Primitive Array (Model)

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 (test)

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"

]}

Primitive Array (shell)

@Entity("programmers")class Programmer { @Id String githubUserName; Name name; Date memberSince; boolean active; int followers; List<String> following;}

@Embeddedclass Name { String first, last;}

@Embedded (model)

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 (test)

> 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 (shell)

@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;}

@Embedded List (model)

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 (test)

> db.programmers.findOne(){

"_id" : "scotthernandez","className" : "demo.Programmer",…"repositories" : [

{"name" : "docs","forkedFrom" : "mongodb/docs"

},{

"name" : "mongo-java-driver","forkedFrom" : "mongodb/mongo-java-

driver"}

]}

@Embedded List (shell)

@Entity("repos")class Repository { @Id ObjectId id; @Reference Programmer owner; String name; String forkedFrom;}

@Reference (model)

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 (test)

> db.repos.findOne(){

"_id" : ObjectId("503297e31aa8255abe542aaa"),"className" : "demo.Repository","owner" : DBRef("programmers", "scotthernandez"),"name" : "docs","forkedFrom" : "mongodb/docs"

}

@Reference (shell)

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 (model)

Programmer scott = new Programmer();//…ds.save(scott);

// save mongodb OrganizationOrganization mongodb = new Organization("mongodb", "mongodb", sdf.parse("Jan 8, 2009"));ds.save(mongodb); // save mongodb's docs RepositoryRepository mongoDocs = new Repository(mongodb, "docs");ds.save(mongoDocs);

// save Scott's forked docs RepositoryRepository scottDocs = new Repository(scott, "docs", mongoDocs);ds.save(scottDocs);

Small schema change (test)

> 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)

> 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"))}

]

Small schema change (shell, 2)

Querying

Find by Equality (test)

• ds.get(Programmer.class, "scotthernandez")

• ds.find(Programmer.class, "userName", "scotthernandez")

• ds.find(Programmer.class).field("userName").equal("scotthernandez”)

Find by Equality (logs)

• test.programmers query: { _id: "scotthernandez" }

• test.programmers query: { userName: "scotthernandez" }

• test.programmers query: { userName: "scotthernandez" }

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"))

Find by Range (logs)

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

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

• test.programmers query: { memberSince: { $lt: new

Date(1262322000000) } }

ds.find(Programmer.class).

field("since").lessThan(dateFmt.parse("Jan 1, 2010")).field("followers").greaterThan(0)

Combining conditions (test)

test.programmers query: { memberSince: { $lt: new Date(1262322000000) }, followers: { $gt: 0 } }

Combining conditions(logs)

Programmer scott = new Programmer("scotthernandez")ds.find(Repository.class).field("owner").equal(scott)

Find by Reference (test)

test.repos query: { owner: { $ref: "programmers", $id: "scotthernandez" } }

Find by Reference (logs)

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(lazy = true) 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

Programmer jeff = createJeff();ds.save(jeff);

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

scott.followers++;ds.save(scott);

Updating with save (test)

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 (logs)

> 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"

}

Updating with save (shell)

@Entitypublic abstract class Member { @Id String userName; @Property("memberSince") Date since; boolean active; String name; @Version Long version;}

Optimistic Concurrency (model)

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 (logs)

> 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")

}

Optimistic Concurrency (shell)

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);

UpdateOperations (test)

update test.programmers

query: { _id: "scotthernandez" }

update: { $inc: { followers: 1 } }

UpdateOperations (logs)

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/

Engineering Manager, 10gen

Jeff Yemin

#MongoBoston

Thank You

top related