Friday, July 18, 2014

$(update)

$(update)
source : http://docs.mongodb.org/manual

Update Values in an Array

Data
db.test.insert([
{ "_id" : 1, "grades" : [ 80, 85, 90, 80 ] },
{ "_id" : 2, "grades" : [ 88, 90, 92, 87 ] },
{ "_id" : 3, "grades" : [ 85, 100, 90, 87 ] }
])

Update 1st value of an array from 80 to 82.
db.test.update(
{ _id : 1, grades : 80},
{ $set : { "grades.$" : 82}}
)
db.test.find({_id: 1})
Result - { "_id" : 1, "grades" : [ 82, 85, 90, 80 ] }

Update the documents that have grades value : 90.
db.test.update(
{ _id : 1, grades : 90},
{ $set : { "grades.$" : 92}},
{ multi : true}
)

Result - No effect of multi : true, only the first document gets updated.
{ "_id" : 1, "grades" : [ 82, 85, 92, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92, 87 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90, 87 ] }

Update Documents in an Array

Data
db.test.insert([
{ "_id" : 4, "grades" : [ { grade: 80, mean: 75, std: 8 },
                          { grade: 85, mean: 90, std: 5 },
                          { grade: 90, mean: 85, std: 3 } ] },
{ "_id" : 5, "grades" : [ { grade: 80, mean: 75, std: 8 },
                          { grade: 85, mean: 90, std: 5 },
                          { grade: 90, mean: 85, std: 3 } ] }
])

1. Use the positional $ operator to update the value of the std field in the embedded document with the grade of 85:
db.test.update(
{ _id: 4, "grades.grade": 85 },
{ $set: { "grades.$.std" : 6 } }
)

db.test.find({ _id: 4}).pretty()
Result
{
        "_id" : 4,
        "grades" : [
                {
                        "grade" : 80,
                        "mean" : 75,
                        "std" : 8
                },
                {
                        "grade" : 85,
                        "mean" : 90,
                        "std" : 6
                },
                {
                        "grade" : 90,
                        "mean" : 85,
                        "std" : 3
                }
        ]
}

2. update multiple docs
db.test.update(
{ "grades.grade": 90 },
{ $set: { "grades.$.std" : 4 } },
{ multi : true}
)

db.test.find().pretty()
{ "_id" : 4, "grades" : [ { grade: 80, mean: 75, std: 8 },
                          { grade: 85, mean: 90, std: 5 },
                          { grade: 90, mean: 85, std: 4 } ] },
{ "_id" : 5, "grades" : [ { grade: 80, mean: 75, std: 8 },
                          { grade: 85, mean: 90, std: 5 },
                          { grade: 90, mean: 85, std: 4 } ] }

Projection

Project Array Values
Source - http://docs.mongodb.org/manual

$(projection) operator limits the contents of the field that is included in the query results to contain the first matching element.

Data
{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] },
{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] },
{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] },
{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] },
{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] },
{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }

Criteria - returns only the first element greater than or equal to 85 for the grades field.
db.students.find( { semester: 1, grades: { $gte: 85 } },
                          { "grades.$": 1 } )
 or
db.students.find( { semester: 1, grades: { $gte: 85 } },
                   { "grades.$": -1 } )

Result
{ "_id" : 1, "grades" : [ 87 ] }
{ "_id" : 2, "grades" : [ 90 ] }
{ "_id" : 3, "grades" : [ 85 ] }

Limitations
1. limits the content of the field to the first element that matches the query document.
2. The field must appear in the query document
3. Only one positional $ operator can appear in the projection document.
4. Only one array field can appear in the query document.

Project Array Documents
Data
{ "_id" : 7, semester: 3, "grades" : [ { grade: 80, mean: 75, std: 8 },
                                       { grade: 85, mean: 90, std: 5 },
                                       { grade: 90, mean: 85, std: 3 } ] },
{ "_id" : 8, semester: 3, "grades" : [ { grade: 92, mean: 88, std: 8 },
                                       { grade: 78, mean: 90, std: 5 },
                                       { grade: 88, mean: 85, std: 3 } ] }

Criteria
db.test.find(
   { "grades.mean": { $gt: 70 } },
   { "grades.$": 1 }
)

Result
{ "_id" : 7, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 8 } ] }
{ "_id" : 8, "grades" : [ { "grade" : 92, "mean" : 88, "std" : 8 } ] }


$elemMatch (projection)
limits the contents of an array field that is included in the query results to contain only the array element that matches the $elemMatch condition.

Data
{
 _id: 1,
 zipcode: "63109",
 students: [
              { name: "john", school: 102, age: 10 },
              { name: "jess", school: 102, age: 11 },
              { name: "jeff", school: 108, age: 15 }
           ]
},
{
 _id: 2,
 zipcode: "63110",
 students: [
              { name: "ajax", school: 100, age: 7 },
              { name: "achilles", school: 100, age: 8 },
           ]
},
{
 _id: 3,
 zipcode: "63109",
 students: [
              { name: "ajax", school: 100, age: 7 },
              { name: "achilles", school: 100, age: 8 },
           ]
},
{
 _id: 4,
 zipcode: "63109",
 students: [
              { name: "barney", school: 102, age: 7 },
           ]
}

Criteria
db.test.find( { zipcode: "63109" },
                 { students: { $elemMatch: { school: 102 } } } )

Result
{ "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
{ "_id" : 3 }
{ "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }

db.test.find( { zipcode: "63109" },
                 { students: { $elemMatch: { school: 102 } }, _id : 0 } )
Result
{ "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
{  }
{ "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }

Note : The document with _id equal to 3 does not contain the students field in the result since no element in its students array matched the $elemMatch condition.

Limitations
If multiple elements match the $elemMatch condition, the operator returns the first matching element in the array.

$slice(projection)

Returns first element
db.test.find( { zipcode : "63109" }, { students: {$slice: 1 } } )

Result
{ "_id" : 1, "zipcode" : "63109", "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
{ "_id" : 3, "zipcode" : "63109", "students" : [ { "name" : "ajax", "school" : 100, "age" : 7 } ] }
{ "_id" : 4, "zipcode" : "63109", "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }

Returns last 2 elements
db.test.find( { zipcode : "63109" }, { students: {$slice: -2 } } )

Result
{ "_id" : 1, "zipcode" : "63109", "students" : [ { "name" : "jess", "school" : 102, "age" : 11 }, { "name" : "jeff", "school" : 108, "age" : 15 } ] }
{ "_id" : 3, "zipcode" : "63109", "students" : [ { "name" : "ajax", "school" : 100, "age" : 7 }, { "name" : "achilles", "school" : 100, "age" : 8 } ] }
{ "_id" : 4, "zipcode" : "63109", "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }

$elemMatch(query)

Array Query

$elemMatch(query) -  matches documents in a collection that contain an array field with at least one embedded document or value that matches all the specified criteria.

Data
{
records: [ { student: "Jane", grade: 90, location : "a" },
  { student: "Jane", grade: 78, location : "b" } ]
},
{
records: [ { student: "Jane", grade: 90, location : "c" },
  { student: "Bob", grade: 78, location : "d" } ]
}

Query
returns all documents in the collection where the records array contains at least one element with both student = Jane and grade > 85.
{ records: { $elemMatch: { student: "Jane", grade: { $gt: 85 } } } }

Result
matches { student: "Jane", grade: 90, location : "a" }  and { student: "Jane", grade: 90, location : "c" }
Both documents are returned.

Tuesday, June 17, 2014

MongoDb - using $sum in aggregation

Data
{ "_id" : 1, "city" : "delhi", "state" : "delhi", "pop" : 10}
{ "_id" : 2, "city" : "chandigarh", "state" : "punjab", "pop" : 10}
{ "_id" : 3, "city" : "delhi", "state" : "delhi", "pop" : 10}
{ "_id" : 4, "city" : "delhi", "state" : "delhi", "pop" : 10}
{ "_id" : 5, "city" : "shimla", "state" : "hp", "pop" : 10}
{ "_id" : 6, "city" : "shimla", "state" : "hp", "pop" : 10}

db.test.aggregate([
{ $group : { _id : "$state", population : { $sum : "$pop"}, count : { $sum : 1}}},
{ $sort : {population : 1}}
])

Result
{ "_id" : "punjab", "population" : 10, "count" : 1 }
{ "_id" : "hp", "population" : 20, "count" : 2 }
{ "_id" : "delhi", "population" : 30, "count" : 3 }

db.test.aggregate([
{ $group : { _id : { state : "$state", city : "$city" }, population : { $sum : "$pop"}, count : { $sum : 1}}},
{ $sort : {population : 1}}
])

{ "_id" : { "state" : "punjab", "city" : "chandigarh" }, "population" : 10, "count" : 1 }
{ "_id" : { "state" : "hp", "city" : "shimla" }, "population" : 20, "count" : 2}
{ "_id" : { "state" : "delhi", "city" : "delhi" }, "population" : 30, "count" :3 }