MongoDB Queries
MongoDB Queries
This command creates the db if it does not yet exist and establishes context for subsequent queries.
4. A collection is created the first time you insert a document into the collection:
o There is no need to declare a schema as in an RDBMS because the documents can have any structure you desire
o insert one document: db.collection-name.insert(document) where document is a JSON object
o insert many documents: db.collection-name.insertMany([document1, document2, ..., document_n])
o mongodb creates an attribute called _id that contains a unique, identifying key for the object
Find Operations
1. The find() function is the workhorse command for querying a mongo database:
2. db.collection-name.find(<query>, <projection>)
a. The query object is a JSON object of the form { ... }. For example:
b. db.inventory.find( { status: "D" } )
i. Equality: { <field1>: <value1>, <field2> : <value2>, ...} -- Returns all documents which have field(s) whose
value(s) matches each of the values in the list. For example:
j. db.inventory.find( { status: "D" } )
k. db.inventory.find( { status: "D", qty: 75 } )
l. Queries that use one or more of the find operators have the form:
m. { <field1>: { <operator1>: <value1> }, ... }
i. For example:
ii. db.inventory.find( { status: { $in: [ "A", "D" ] } } )
iii. db.inventory.find( { status: "A", qty: { $gt: 10, $lt: 30 } } )
iv. An example with the OR operator--notice the use of a list ([]) here
v. db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )
This query returns all documents that do not have a status field
n. Sorting: Add the .sort() function and use 1 to indicate an ascending field and -1 to indicate a descending field
o. db.inventory.find({}).sort({ qty: 1 })
sorts the final results in ascending order by status and in case of ties in descending order by qty
p. For the following example queries use the following collection:
db.inventory.insertMany( [
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);
i. Equality query
ii. db.inventory.find( { "size.uom": "in" } )
returns all documents whose size document has a "uom" attribute with the value of "in"
When querying using dot notation, the field and nested field must be inside quotation marks.
iii. AND query
iv. db.inventory.find( { "size.h": { $lt: 15 }, "size.uom": "in", status: "D" } )
q. Queries on attributes whose values are arrays (i.e., multi-valued attributes): when you query an array, you will get
all documents whose arrays match the query--the arrays that are returned with the documents will not be projected
so that only elements satisfying the query are returned--all array elements will be returned. There are projection
functions that can limit the number of returned array elements, but you cannot return exactly those array elements
that match the query filter.
Use the following collection to execute the example queries in this section:
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },
{ item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] },
{ item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },
{ item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },
{ item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }
]);
i. Query if an array field contains at least one element with the specified value:
ii.
iii. db.inventory.find( { tags: "red" } )
iv. Query if an array field contains any of several values
v.
vi. db.inventory.find( { tags: { $in : ["blank", "blue"] } } )
vii. Exact Match: order of tags is important and array must contain exactly those items db.inventory.find( { tags:
["red", "blank"] } ) Only the document with "notebook" gets returned.
viii. Exact Match: order of tags is unimportant and array must contain each of those items (it may contain
additional items as well)
ix.
x. db.inventory.find( { tags: { $all: ["red", "blank"] } } )
xi. Query an Array with Multiple Filter Conditions and return all documents where the array values in
combination satisfy the filter conditions
xii. db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )
Returns any documents where one array element is > 15 and one array element is < 20. All of the following
arrays would work:
Now [ 10, 17 ] satisfies the query but [10, 25, 40] does not
i. Query on a specific field: use dot notation with the name of the array and then the attribute in the embedded
document:
ii. db.inventory.find( { 'instock.qty': { $lte: 20 } } )
This query return all documents where at least one of the instock objects has a qty field ≤ 20.
iii. Use $elemMatch if the query should succeed only if a nested document satisfies all of the query conditions
iv. db.inventory.find( { "instock": { $elemMatch: { qty: 5, warehouse: "A" } } } )
This query matches any document where at least one of the instock objects has a qty of 5 and a warehouse
equal to "A".
The above query only matches instock objects that have exactly these two fields, in exactly this order, and
with exactly these values
Another example, this time where we want any documents that have an instock object that matches the
condition: 10 < qty ≤ 20
db.inventory.find( { "instock": { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } } )
v. Queries in which a combination of nested documents satisfies the filter criteria: If you do not use the
$elemMatch operator, then when you specify a list of filter conditions, it is permissable for different objects
in the array to match the conditions
vi. db.inventory.find( { "instock.qty": { $gt: 10, $lte: 20 } } )
This query will be true if there is either one instock object whose qty field is between 10 and 20 or if there
are two instock objects such that one's qty field is > 10 and the second's qty field is ≤ 20 (e.g., one whose qty
field is 50 and one whose qty field is 5).
Another example that shows how subtle changes to the operators produce much different results:
db.inventory.find( { "instock.qty": 5, "instock.warehouse": "A" } )
Again we query on the qty and warehouse fields but now this query is true if there are two instock objects
such that one's qty field is 5 and the other's warehouse field is "A". Of course it is also true if one instock
object meets both conditions.
4. Projection: If you want to only print certain attributes in the returned documents you can include attributes by specifying
their name and a 1 and you can exclude attributes by specifying their name and a 0. For example:
5. db.inventory.find( { status: "A" }, { item: 1, status: 1 } )
Prints all fields except the status and instock fields In general:
o attribute-name: 1 -- includes the attribute in the printed query results
o attribute-name: 0 -- excludes the attribute in the printed query results
With the exception of the _id field, you cannot combine inclusion and exclusion statements in projection documents.
Returns the item, status, and _id attributes in the outermost document and the uom attribute from the object
embedded in the size field.
h. Return Specific Fields from Documents Embedded in an Array (show the following query in the Mongo DB shell)
i. db.inventory.find( { status: "A" }, { item: 1, status: 1, "instock.qty": 1 } )
Prints the instock array as a list of objects but only the qty field appears
j. Ways to restrict the values returned from an array: There is no way to restrict array results to the ones that satisfy a
query filter but you can use the $, $elemMatch, and $slice operators to somewhat restrict the results.
The operation returns documents that have zipcode equal to 63109 and prints the first student from the students
array whose school is 102.
The following query uses this schema:
For each student, $ returns the first object from the grades array whose mean is > 70 and whose grade is > 90
db.students.find( { grades: { $slice: 5 } } )
returns the first five documents from each student's grade array. It returns all documents from a student's grade
array if there are fewer than 5 documents in that array.
You can do more things with slice, like return a range by skipping some number of entries or return the last
documents in an array by using a negative number.
Aggregation Operation
Mongo DB provides three ways to perform aggregation
1. Aggregation pipeline: Query result sets are passed through a pipeline, with the output of one operator becoming the input
to the next operator
a. Go to this link--https://docs.mongodb.com/manual/aggregation/--for an animated example of how the following
query executes
b. db.orders.aggregate([
c. { $match: { status: "A" } },
d. { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
e. ])
i. First Stage: The $match stage filters the documents by the status field and passes to the next stage those
documents that have status equal to "A".
ii. Second Stage: The $group stage groups the documents by the cust_id field to calculate the sum of the
amount for each unique cust_id. The final fields are named _id and total.
iii. Further notes on this query:
1. $group uses the _id field to perform its grouping. The _id field is required
2. To specify a field in an aggregation operation, put a $ in front of it, as is done with $cust_id and
$amount
3. You need to put quotes around the attribute fields that you are aggregating on.
Another example:
db.inventory.insertMany([
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "journal", qty: 25, size: { h: 16, w: 21, uom: "cm" }, status: "F" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 100, size: { h: 15, w: 15.25, uom: "cm" }, status: "A" },
{ item: "postcard", qty: 75, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);
The first aggregate query counts the number of times each item occurs. Note that we get a count on the number of
documents by $summing 1. Don't try to count using the $count function--it does not work with the group operator.
The second aggregate query counts the quantity of each item and the third aggregate query computes the average
height of each item.
This prints the item twice, once as _id and once as item but it's the only field that will be the same for all
documents in a group. For example the status, qty, and size fields are different for each document.
o. Computing an aggregate function for a field that is an array: If you want to compute an aggregate function for a
field that is an array or an array of embedded documents, you must use the $unwind operator to create a duplicate
tuple for each array element (the only field that differs is the array field), then perform the aggregation operation.
For example, create the following document
db.inventory.insertMany([{ _id: 1, "item" : "shirt", sizes: [ 10, 15, 20] },
{ _id: 2, "item" : "pant", sizes: [ 32, 34, 36, 40] }])
To compute the minimum size for each item, you can write:
db.inventory.aggregate([{ $unwind : "$sizes" },
{ $group : { _id : "$item",
minSize : { $min : "$sizes" }
} } ] )
Here is a sample map-reduce query that sums the amount of orders for each customer whose status is "A" (go to the above
link to see a pictorial illustration of how this query executes).
db.orders.mapReduce(
map → function() { emit( this.cust_id, this.amount ); },
reduce → function(key, values) { return Array.sum( values ); },
{
query → query: { status: "A" },
output → out: "order_totals"
}
)
In this query the key parameter matches this.cust_id and the values parameter matches this.amount
For most aggregation operations, the Aggregation Pipeline provides better performance and more coherent interface.
However, map-reduce operations provide some flexibility that is not presently available in the aggregation pipeline.
Updating Documents
For detailed information on updating documents, go to https://docs.mongodb.com/manual/tutorial/update-documents/
1. db.collection.updateOne(<filter>, <update>, <options>): updates the first document that matches the filter.
2. db.collection.updateMany(<filter>, <update>, <options>): updates all documents that match the filter.
3. db.collection.replaceOne(<filter> <update>, <options>): replaces the first document matched by the filter by a new
document.
{
"_id" : 5,
"quizzes" : [
{ "wk": 1, "score" : 10 },
{ "wk": 2, "score" : 8 },
{ "wk": 3, "score" : 5 },
{ "wk": 4, "score" : 6 }
]
}
The following command will add a new document to the quizzes array:
db.students.update(
{ _id: 5 },
{ $push: { quizzes: { "wk" : 5, "score" : 7 } } }
)
c. If you want to update a document in an array and you know its exact location in the array, then you can use a
positional index. The first document is at index 0. For example to change the third quiz to be the document {wk :
8, score: 10} I could write:
d. db.students.update(
e. { _id: 5},
f. { $set : { "quizzes.2" : { wk : 8, score : 10 } } }
g. )
h. If instead I want to modify some of the fields of an array document but not replace it, then I can use the positional
syntax shown above and append the field name. For example, given the above set of quizzes for a student, you can
update the score field in the third quiz to 7 and the wk field in the fourth quiz to 6 using the following command:
i. db.students.update(
j. {_id : 5},
k. { $set : { "quizzes.2.score" : 7 ,
l. "quizzes.3.wk" : 6 } }
m. }
n. Finally suppose you do not know the exact position of a document but you know the value of one of the fields in
the document that needs to change. For example, suppose we want to change the score of the wk 3 quiz to 7. Then
we use the positional operator $ which acts as a placeholder for the first array document that matches the query
filter.
o. db.students.update(
p. {_id : 5, "quizzes.wk" : 3},
q. { $set : { "quizzes.$.score" : 7 } }
r. )
Deletion
The relevant commands for deletion are:
filter can be any of the filters previously discussed for the find command.