# Mongo Module
Employee Collection :
We will be using the below collection to understand mongo operations:
collection Employee {
property empId : Id
property firstName:String
property dob:CalendarDate
property salary:Int
property designation:CompanyData::Designation
}
# CRUD Operations
# 1. CREATE : Creating a employee record :
def addEmployee(_id:String, firstName:String, dob:CalendarDate, salary:Int, designation:CompanyData::Designation): Unit = {
val employeeRow = EmployeeRow( // creating a employee row
_id = id,
firstName = firstName,
dob = dob,
salary = salary,
designation= designation
)
EmployeeWriter().save(employeeRow) // writing to db
}
# 2. READ : Reading a record from database
Eg : Find the employee whose ID is 001
EmployeeQuery()._id.is(“001”).find()
# 3. UPDATE: Update a record in database collection
val q = EmployeeQuery()._id.is(“001”) // Finding a record which needs to be updated.
val u = EmployeeUpdate().salary.set(1000) // Updating salary to 1000
EmployeeWriter().updateOne(q,u)
# 4. REMOVE: Removing a record from database collection
val query = EmployeeQuery().name.is(“john”) // Finding a record which needs to be removed.
EmployeeWriter.remove(query)
# CREATE : Creating a row and writing it to collection in DB
- User EmployeeRow for creating a row in the employee collection, which is like a holder to create the employees data.
- Use EmployeeWriter to write the data to the DB.
val employeeRow = EmployeeRow(
_id = empId,
firstName = firstName,
dob = dob,
salary = salary,
designation= designation
)
EmployeeWriter().save(employeeRow)
# save() vs insert()
insert(): Always ADDS a row to the collection.
save(): Either ADDS a row or UPDATES if a row already exists with the provided _id.
// ADDS a row to the collection -> If NO row exists with the provided `_id`
// .save() and .insert() acts the same way as in this case id is always generated.
val employeeRow = EmployeeRow(
_id = new Id(), // newly generated id
firstName = firstName,
dob = dob,
salary = salary,
designation= designation
)
EmployeeWriter().save(employeeRow) // ADD a new row
OR
EmployeeWriter().insert(employeeRow) // ADD a new row
val employeeRow = EmployeeRow(
_id = id,
firstName = firstName,
dob = dob,
salary = salary,
designation= designation
)
// ADDS a row to the collection -> If NO row exists with the provided `_id`
// UPDATES an existing row -> If a row already exists with the provided `_id`
EmployeeWriter().save(employeeRow)
OR
// ADDS a row to the collection -> If NO row exists with the provided `_id`
// Throws DuplicateEntryKey Error -> If a row already exists with the provided `_id`
EmployeeWriter().insert(employeeRow)
Note:
Mongo generates its own _id if it's not provided.
# insertOne() vs insertMany()
- InsertOne is used when you want to add only one record into the collection
val employeeRow = EmployeeRow(
_id = id,
firstName = firstName,
dob = dob,
salary = salary,
designation= designation
)
EmployeeWriter().insertOne(employeeRow)
- InsertMany is used when you want to add multiple records at once into the collection
val _id1 = new Id();
val _id2 = new Id();
val _id3 = new Id();
val employeeRow1 = EmployeeRow(
_id = id1,
firstName = "john",
dob = 12-12-2012,
salary = 1000,
designation= SE
)
val employeeRow2 = EmployeeRow(
_id = id2,
firstName = "ron",
dob = 13-02-1996,
salary = 20000,
designation= SSE
)
val employeeRow3 = EmployeeRow(
_id = id3,
firstName = "steve",
dob = 3-06-1995,
salary = 40000,
designation= CEO
)
EmployeeWriter().insertMany(employeeRow1,employeeRow2,employeeRow3)
# Query : Reading a record from data base
# find()
- Find on a query returns a list of all matching records from the collection.
- If no matching records are found it returns an empty list.
// The above example returns the record of all employees whose salary is 1000.
val q = EmployeeQuery().salary.is(1000).find()
output : List[EmployeeRow]
# findOne()
- FindOne on a query returns only one record, i.e the first matching occurrence of the matching record.
- If no value is found it returns a None , therefore findOne() is an
Option[<Row>].
\\ The above example returns the first matching record whose salary is 1000 else it returns None.
val q = EmployeeQuery().empId.is("A001").findOne()
output : Option[EmployeeRow]
- Since we have got a optional field
- We can return a option i.e
Option[EmployeeRow]. - We can do a
.getand returnEmployeeRowif the employees existance is already checked in pre condition.
- We can return a option i.e
- we can use asc and desc methods to arrange the records in ascending / descending order and then findOne().
val q = EmployeeQuery().designation.is("SE").dob.desc.findOne()
output : Option[EmployeeRow]
# limit()
- Limit method limits the number of records to be returned or passed to the next query builder.
val q = EmployeeQuery().designation.is("SE").limit(5).find()
output : List[EmployeeRow]
- Returns <= 5 records from the collection which matches the query.
# Query Building
val q1 = EmployeeQuery().designation.is(“SE”)
val q2 = q1.salary.lessOrEqual(10000)
val q3 = q1.salary.greaterOrEqual(5000)
q3.find() // list of employees with designation SE and salary <=10000 and >= 5000
q2.find() // list of employees with designation SE and salary <=10000 and >= 5000
q1.find() // list of employees with designation SE and salary <=10000 and >= 5000
- q2 is the query for designation SE and salary <= 10000
- find() gives list of employees with designation SE and salary <=10000 and >= 5000 but it looks like it only gives designation SE and salary >= 5000 which is an most important point to note, if not taken care gives wrong data.
- MongoQuery is a builder i.e no new query is created just by creating a new variable, it just appends the query.
- q1 = q1 = q3
- If you want to do q2 and q3 independently without appending to q1 :
- Use copy method
val q1 = EmployeeQuery().designation.is(“SE”)
val q2 = q1.copy.salary.lessOrEqual(10000).find()
val q3 = q1.copy.salary.greaterOrEqual(5000).find()
# Points To note
val q1 = EmployeeQuery().designation.is(“SE”).salary.lessOrEqual(10000).find()
val q2 = EmployeeQuery().designation.is(“SE”).salary.greaterOrEqual(5000).find()
val q3 = EmployeeQuery().designation.is(“SE”).name.is("john").find()
- In the above example for the 3 queries “EmployeeQuery().designation.is(“SE”)” is common , so its a best practice to move the query to a separate variable and use the variable with copy method.
val qDesig = EmployeeQuery().designation.is(“SE”)
// **** DON'T FORGET TO USE COPY ****
val q1 = qDesig.copy.salary.lessOrEqual(10000).find()
val q2 = qDesig.copy.salary.greaterOrEqual(5000).find()
val q3 = qDesig.copy.name.is("john").find()
val q1 = EmployeeQuery().designation.is(“SE”).salary.lessOrEqual(10000).findOne
if(q1 != None) {
Println(“got the data”)
}else
{
Println(“data not found”)
}
- Always try to avoid
ifconditions in the code instead ofifpattern matching can be used :
val q1 = EmployeeQuery().designation.is(“SE”).salary.lessOrEqual(10000).findOne
q1 match {
case Some(employeeRow) => Println(“got the data”)
case None = > Println(“data not found”)
}
# Indexing
- Indexes support the efficient execution of queries in MongoDB.
- Without indexes, MongoDB must perform a collection scan, i.e. scan every document in a collection, to select those documents that match the query statement.
- If an appropriate index exists for a query, MongoDB can use the index to limit the number of documents it must inspect.
- Indexes are special data structures that store a small portion of the collection’s data set in an easy to traverse form.
- Without Indexing Example :
- With Indexing Example:
Indexing designation :
collection Employe {
property id : Id
property firstName:String
property dob:CalendarDate
property salary:Int
property designation:CompanyData::Designation
index desingationIdIndex {
up designation
}
}
# lazyFind()
- todo
# Update
# updateOne
- Used to update the existing row in a collection.
- It takes two parameters the query criteria and the update modifications to apply.
val q = EmployeeQuery()._id.is("A001") // query employee with A001 as employee Id
val u = EmployeeUpdate().salary.set(20000) // update salary to 20000
EmployeeWriter().updateOne(q,u)
# updateMulti
- Used to update the existing rows in a collection.
- It takes two parameters the query criteria and the update modifications to apply.
val q = EmployeeQuery().designation.is("SE") // query employee designation = SE
val u = EmployeeUpdate().designation.set("SSE") // change designation to SSE
EmployeeWriter().updateMulti(q,u)
- updates all employees whose designation is “SE” to “SSE”
# Delete
# remove()
- Removes documents from a collection.
- Eg : Remove with no Arguments
EmployeeWriter().remove()
- Removes all the rows from the employee collection.
- Remove also takes a query for deleting rows which match it.
- Eg : Remove with argument (query)
val q = EmployeeQuery().designation.is("SE").salary.is(10000)
EmployeeWriter().remove(q)
- Removes all the marching query.
- removeById takes a smile Id as a parameter to delete the particular row.
# drop()
EmployeeWriter().drop()
- Drops the employee database collection.