Transcript
Page 1: MongoDB Munich 2012: MongoDB for official documents in Bavaria

MongoDB@BayernMigration from RDBMS, Problems, Unit-Testing

Page 2: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Christian Brensing

Bayerisches Landesamt für Statistik und Datenverarbeitung

IuK / Rechenzentrum Süd

Page 3: MongoDB Munich 2012: MongoDB for official documents in Bavaria

• Template-Processor (~ JSP)

• ODF and RTF

• PDF / PostScript postprocessing

• Groovy, Python, Ruby, Tcl

• In Production using RDBMS since 2008

• Central HR system (SAP) uses BayText to create output

Page 4: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Client for developing the templates (BayText-IDE)

Page 5: MongoDB Munich 2012: MongoDB for official documents in Bavaria

ODF-Template using Ruby

Page 6: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Generated document

Page 7: MongoDB Munich 2012: MongoDB for official documents in Bavaria

2 MillionGenerated documents per year

Page 8: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Tiny dataset50,000 records and 10 GB BLOB

Page 9: MongoDB Munich 2012: MongoDB for official documents in Bavaria

a small system after all

Page 10: MongoDB Munich 2012: MongoDB for official documents in Bavaria

So why migrate?

Page 11: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Because we can

Page 12: MongoDB Munich 2012: MongoDB for official documents in Bavaria

developers.pop()Smaller teams

Page 13: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Easy to learnRead one book and you're done

Page 14: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Simple mapping

Page 15: MongoDB Munich 2012: MongoDB for official documents in Bavaria

nodes

groups

templates

document_usages

folder_configurations

codes

permissions

requests

documents

folders

structures template_tags

roles

roles_roles

bundles

componentsdynafields

scripts

Page 16: MongoDB Munich 2012: MongoDB for official documents in Bavaria

nodes

roles

properties

GridFS

Page 17: MongoDB Munich 2012: MongoDB for official documents in Bavaria

{! "_id" : ObjectId(),! "_type" : "Document",! "updated_at" : ISODate("2007-12-06T10:04:00.543Z"),! "updated_by" : "maggie",! "version" : 1,! "path" : "foo.bar.Document",! "description" : "",! "language" : "ruby",! "format" : "odf",! "autoload_uplevel" : -1,! "requests" : [! {! "name" : "Test",! "description" : "foo", ! "xml" : zlib("<?xml ...?>")! }, ! ... ! ],! "structure" : [! { ! "alias" : "some alias",! "component_path" : "foo.bar.Document$Document",! "parent", -1 ! },! ... ! ], ! } ! "tags" : ["foo", "bar", "baz"]!}

Page 18: MongoDB Munich 2012: MongoDB for official documents in Bavaria

public class RoleReadConverter implements Converter<DBObject, Role> {! @Override! public Role convert(DBObject source) {! Role role = new Role();! role.setName((String) source.get("name"));! ...! return role;! }!}!!!public class RoleWriteConverter implements Converter<Role, DBObject> {! @Override! public DBObject convert(Role source) {! return new BasicDBObject()! .append("name", role.getName())! .append(...);! }!}!!!// Convert a DBObject to an Entity!conversionService.convert(collection.findOne(...));

Easy mapping using Spring-ConversionService

Page 19: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Performanceup to 10x

Page 20: MongoDB Munich 2012: MongoDB for official documents in Bavaria

ORM no moreThe MongoDB driver is all you need

Page 21: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Obstacles?

Page 22: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Mentality

Page 23: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Referential IntegrityMulti-Document-Update on denormalized schema

Page 24: MongoDB Munich 2012: MongoDB for official documents in Bavaria

{! "_id" : ObjectId(),! "_type" : "Folder", ! "updated_at" : ISODate("2007-12-06T10:04:00.543Z"),! "updated_by" : "maggie",! "version" : 1,! "path" : "foo.bar.Folder",! "description" : "bla",! "bundles" : [! ... ! ]! "document_usages" : [! {! "name" : "foo",! "description" : "bla", ! "exec_order" : 5, ! "print_copies" : 2,! "type": "FAIR_COPY",! "document_path" : "a.b.Document",! "bundle" : "bar"! },! ...!}

Linking documents via a path instead of ObjectId

Page 25: MongoDB Munich 2012: MongoDB for official documents in Bavaria

But paths are mutable!All references must be updated

Page 26: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Approach

• Pseudo-Transaction with an update locking mechanism in a custom oplog collection

• Periodical repair jobs finishing failed operations • Extended interpretation of eventual consistency

Page 27: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Unit-TestsContinuous Integration

Page 28: MongoDB Munich 2012: MongoDB for official documents in Bavaria

F.I.R.S.T.

Page 29: MongoDB Munich 2012: MongoDB for official documents in Bavaria

IsolatedTests are using a unique DB per JVM

Page 30: MongoDB Munich 2012: MongoDB for official documents in Bavaria

@Configuration!@Profile("test")!public class TestSpringConfiguration extends SpringConfiguration {! @Override! public void init() {! setTestProperties();! ! super.init();! ! // Delete test db! db().dropDatabase();! }! ! private void setTestProperties() {! String dbname = env.getProperty("db.name", "baytext_test_" + getSimpleUsername());! String host = env.getProperty("db.host", "mongodb-dev.db.rz-sued.bybn.de");! String port = env.getProperty("db.port", "27016");! ! cmProperties.setProperty("servers", String.format("%s:%s", host, port));! cmProperties.setProperty("name", dbname);! }!! // OS-Username without prefix (e.g. maggie instead of lfstad-maggie)! private static String getSimpleUsername() {! String username = SystemUtils.USER_NAME;! int indexOfDash = username.indexOf('-');! return indexOfDash != -1 ? username.substring(indexOfDash + 1) : username;! }!}

Test-ApplicationContext

Page 31: MongoDB Munich 2012: MongoDB for official documents in Bavaria

RepeatableCollections are dropped before each test method

Page 32: MongoDB Munich 2012: MongoDB for official documents in Bavaria

public class MongoTestExcecutionListener extends AbstractTestExecutionListener {! @Override! public void beforeTestMethod(TestContext testContext) throws Exception {! purgeCollections();! }! ! private void purgeCollections() {! DB db = MongoDBHolder.getDB();! for (String collectionName : db.getCollectionNames()) {! if (collectionName.startsWith("fs.") || collectionName.startsWith("system.")) {! continue;! }! DBCollection collection = db.getCollection(collectionName);! if (!collection.isCapped()) {! collection.drop();! }! }! }!}

Spring-TestExecutionListener

Page 33: MongoDB Munich 2012: MongoDB for official documents in Bavaria

@RunWith(SpringJUnit4ClassRunner.class)!@ActiveProfiles({"test"})!@ContextConfiguration(classes = TestSpringConfiguration.class)!@TestExecutionListeners({! DependencyInjectionTestExecutionListener.class,! DirtiesContextTestExecutionListener.class,! MongoTestExcecutionListener.class!})!public abstract class MongoTestSupport {!}!!!!public class DocumentRepositoryTest extends MongoTestSupport {!}!

Test base class

Page 34: MongoDB Munich 2012: MongoDB for official documents in Bavaria

95% Coverage

Page 35: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Summary

• Developing the data layer is fun again • Reduced complexity • Flat learning curve compared to SQL/ORM • use_mongo() unless transactions_required

Page 36: MongoDB Munich 2012: MongoDB for official documents in Bavaria

Thank you!


Recommended