type-safe mongodb query (lift rogue query)

Post on 30-Oct-2014

3.301 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Type-safe query is internal Scala DSL for constructing and executing find and modify commands against MongoDB in the Lift web framework.

TRANSCRIPT

Abdhesh Kumarabdhesh@knoldus.com

Type-Safe Mongo Query(Rogue Query)

1. What is type-safe?

2. What is Mongo Record?

3. What is native Mongo query?

4.What is the Rogue query?

5. Installation

6. SetUp

7. Query Examples

Agenda

What is Type-safe?-> It’s type safe meaning, for example, if you try to use an Int

where a String is expected in a function or query.

A type error is erroneous or undesirable program behaviour caused by a discrepancy

between differing data types for the program's constants, variables, and methods

(functions), e.g., treating an integer (int) as a floating-point number (float)

def typeSafeFunction(param: String): Unit ={....}

You can not call this function by passing any value other than String

ex. typeSafeFunction(23),typeSafeFunction(43.3434),typeSafeFunction(User)

Mongo Record

Mongo Record is ORM layer for Lift. Lift’s Record class represents

a database record(mongo collections), and MetaRecord trait provides “static” methods for querying and updating records in a

fully expressive way.

Mongo Record...

object Student extends Student with MongoMetaRecord[Student]

class Student extends MongoRecord[Student] with ObjectIdPk[Student] {

def meta: Student.type = Student

object name extends StringField(this, 200)

object age extends IntField(this)

object address extends StringField(this, 200)

object scores extends BsonRecordListField(this, Score)

def toJson = this.asJSON}

Mongo Record...

object Score extends Score with BsonMetaRecord[Score]

class Score extends BsonRecord[Score] { def meta: Score.type = Score object examtype extends StringField(this, 50)

object score extends DoubleField(this)}

Mongo Query

1. find all documents db.students.find()

2. find student that has age 20 yearsdb.students.find({age:20})

3. find students that has more than 25 yearsdb.students.find({age:{"$gte":25}})

4. find students that has more than 40% in quiz

db.students.find({"scores":{"$elemMatch"{"score":"$gt":40},"examtype":"quiz"}}})

Scala Query Againts MongodbLift’s MongoMetaRecord trait provides a findAll() method that lets you pass in a query as a JSON object (MongoDB queries are in fact JSON objects), returning a list of records.

For example, using lift’s JsonDSL, we can do:Student.findAll((Student.name.name -> "Bao Ziglar") ~ (Student.age.name ->( “$gt”->25)))

which is equivalent to

Student.findAll("{ name : “Bao Ziglar”, age : { $gt : 25 } }")

BUTThis would also run by mongo server

Student.findAll((Student.name.name -> "Bao Ziglar") ~ (Student.age.name -> “Farji25”))It's not a valid query and it happily executes for you, returning nothing, never informing you that the age field is not a String but a Int representing the age of the Student.

Typesafe Query->There should be someting here that enforce to use query in typesafe sense

-> Scala compiler should detected field type againts records, fields, conditions and Operands

Student.where(_.name eqs “studentName”).and(_.age eqs "Farji25").fetch

It through the scala error type mismatch; found : String("Farji25") required: Int

Mongo would allow that query and fail to find results at runtime, but Rogue enables Scala to reject the query at compile time.

Rogue Query(Typesafe query)

-> Rogue is a type-safe internal Scala DSL for constructing and executing find and modify commands against MongoDB in the Lift web framework.

-> It is fully expressive with respect to the basic options provided by MongoDB's native query language, but in a type-safe manner

-> Rogue was initially developed by Foursquare Labs for internal use nearly all of the MongoDB queries in foursquare's code base go through this library.

Rogue Query(Typesafe query)...

The Rogue query (typesafe query) enforces the following Constraints:

->The fields must actually belong to the record (e.g., age is a field on the Student record)

->The field type must match the operand type (e.g., age is an IntField)

-> The operator must make sense for the field type (e.g., scores is a MongoListField[String])

->The value specified in the query clause is the same type as the field type (or is appropriate for the operator)

Installation

val rogueField = "com.foursquare" %% "rogue field" % "2.2.0" intransitive()

val rogueCore = "com.foursquare" %% "rogue core" % "2.2.0" intransitive()

val rogueLift = "com.foursquare" %% "rogue lift" % "2.2.0" intransitive()

val rogueIndex = "com.foursquare" %% "rogue index" % "2.2.0" intransitive()

val liftMongoRecord = "net.liftweb" %% "lift mongodb record" % "2.4"

SetUp and Typesafe query

Import package:import com.foursquare.rogue.LiftRogue._

Typesafe query:

Student.where(_.name eqs stdName).and(_.age eqs 25).fetch

Student.where(_.name eqs stdName).

and(_.scores elemMatch (_.score gte 25, _.examtype eqs "quiz")).fetch

Rogue QueryImport package:

import com.foursquare.rogue.LiftRogue._

Typesafe query:

Student.where(_.name eqs stdName).and(_.age eqs 25).fetch

equivalent to:

db.students.find({ "name" : "stdName" , "age" : 25})

Student.where(_.name eqs stdName).and(_.scores elemMatch (_.score gte 25, _.examtype eqs "quiz")).fetch

equivalent to:

db.students.find({ "name" : "stdName" , "scores" : { "$elemMatch" : { "examtype" : "quiz" , "score" : { "$gte" : 25.0}}}})

Rogue Query..

Student.where(_.name matches Pattern.compile(Pattern.quote(stdName), Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)).fetch

Equivalent :

db.students.find({ "name" : { "$regex" : "\\QstdName\\E" , "$options" : "im"}})

Rogue support.

Type safe rogue support all mongodb operators:

Like. Eqs, neq,lt,gt,in,nin,exists,startsWith, regex,all, in, size, contains, at

,BsonRecordField subfield queries

References

http://engineering.foursquare.com/2011/01/21/rogue-a-type-safe-scala-dsl-for-querying-mongodb/

https://github.com/foursquare/rogue

Thanks

top related