I've been working on my Scala application that connects to MySQL on one end (using EclipseLink and JPA), and MongoDB on the other (using Morphia). The
source code is available on GitHub.
In this post I will show you my setup.
build.gradle
Dependencies...
// ...
repositories {
mavenLocal()
mavenCentral()
mavenRepo name: "EclipseLink", url: "http://download.eclipse.org/rt/eclipselink/maven.repo/"
mavenRepo name: "MongoDB", url: "http://morphia.googlecode.com/svn/mavenrepo"
mavenRepo name: "Audiolicious", url: "https://github.com/m1key/repo/raw/master/releases"
}
dependencies {
compile group: 'org.eclipse.persistence', name: 'eclipselink', version: '2.3.0'
compile group: 'org.eclipse.persistence', name: 'javax.persistence', version: '2.0.0'
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.18'
compile group: 'org.mongodb', name: 'mongo-java-driver', version: '2.7.3'
compile group: 'com.google.code.morphia', name: 'morphia', version: '0.99'
// …
}
// ...
Persistence provider
This is how you expose Mongo to your repositories (or DAOs).
package me.m1key.audioliciousmigration.persistence.mongodb
import com.google.code.morphia.Datastore
import com.mongodb.Mongo
import com.google.code.morphia.Morphia
import me.m1key.audioliciousmigration.entities.mongodb.MongoDbSong
class ProductionMorphiaMongoDbPersistenceProvider extends MorphiaMongoDbPersistenceProvider {
private var datastore: Datastore = null
private var mongo: Mongo = null
def initialise(): Unit = {
mongo = new Mongo("localhost", 27017)
datastore = new Morphia().map(classOf[MongoDbSong]).createDatastore(mongo, "audiolicious")
datastore.ensureIndexes()
}
def getDatastore(): Datastore = {
return datastore
}
def getMongo(): Mongo = {
return mongo
}
}
Repository using getDatastore
This is a repository which uses the MongoDB datastore.
package me.m1key.audioliciousmigration.repository
import com.google.inject.Inject
import me.m1key.audioliciousmigration.persistence.mongodb.MorphiaMongoDbPersistenceProvider
import scalaj.collection.Imports._
import me.m1key.audioliciousmigration.entities.mongodb.MongoDbSong
import com.google.code.morphia.query.UpdateOperations
import com.google.code.morphia.query.Query
class MorphiaMongoDbRepository @Inject() (private val persistenceProvider: MorphiaMongoDbPersistenceProvider) {
def save(song: MongoDbSong): Unit = {
val datastore = persistenceProvider.getDatastore()
val selectQuery = datastore.createQuery(classOf[MongoDbSong])
.field("name").equal(song.name).field("albumName").equal(song.albumName)
.field("artistName").equal(song.artistName).field("songKey").equal(song.songKey);
val existingSong = selectQuery.get()
if (existingSong != null) {
var ops = datastore.createUpdateOperations(classOf[MongoDbSong])
if (song.genre != null) {
ops = ops.set("genre", song.genre)
}
if (song.year != 0) {
ops = ops.set("year", song.year)
}
if (song.songArtistName != null) {
ops = ops.set("songArtistName", song.songArtistName)
}
val stat = song.statsList.get(0)
existingSong.addOrEditStats(stat.libraryUuid, stat.percentage, stat.playCount, stat.skipCount)
ops.set("statsList", existingSong.statsList)
val updatedCount = datastore.update(selectQuery, ops).getUpdatedCount()
if (updatedCount != 1) {
println("Warning. Song updated [%d] times while expected once: [%s]".format(updatedCount, song))
}
} else {
datastore.save(List(song).asJava)
}
}
}
getMongo
Here's code that uses getMongo for executing a raw query.
def mine(): Option[Int] = {
val mongo = persistenceProvider.getMongo
val result = mongo.getDB("audiolicious").eval(query)
result match {
case double: java.lang.Double => return Some(double.intValue())
case _ =>
println("Error while obtaining stats. Result of unknown type [%s].".format(result))
return None;
}
}
Putting it all together...
Before code using datastore or mongo can be executed, the following call has to be made.
val mongoDbPersistence = injector.getInstance(classOf[MorphiaMongoDbPersistenceProvider])
mongoDbPersistence.initialise
(This example is using Guice)
I don't know if this is the best way of doing things, but there's little documentation available. This way works. If you have a better idea - definitely let me know!