Last modified: September 29, 2019
This article is written in: 🇺🇸
Querying NoSQL databases requires a different approach compared to relational databases due to their diverse data models and storage mechanisms. This guide focuses on MongoDB, a popular NoSQL database, and explores how to query data effectively using its powerful query language.
After reading the material, you should be able to answer the following questions:
find
, countDocuments
, and distinct
) and advanced queries (such as aggregation, text search, and geospatial queries) in MongoDB?explain()
method in MongoDB, and how can it be used to analyze and optimize query execution plans?Example Document:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "John Doe",
"age": 30,
"email": "john.doe@example.com",
"addresses": [
{
"street": "123 Main St",
"city": "Anytown",
"zip": "12345"
},
{
"street": "456 Elm St",
"city": "Othertown",
"zip": "67890"
}
]
}
Examples of Query Operators:
$eq
, $ne
: Equal, Not Equal$gt
, $gte
, $lt
, $lte
: Greater Than, Greater Than or Equal, Less Than, Less Than or Equal$in
, $nin
: In, Not In$and
, $or
, $not
, $nor
: Logical Operatorsfind
method retrieves documents from a collection that match specified filter criteria.find
is db.collection.find(query, projection)
, where query
specifies selection criteria and projection
determines the fields to include or exclude.Example: Retrieve all users aged 25
Sample Data in users
Collection:
Suppose we have the following documents in our users
collection:
db.users.insertMany([
{ _id: 1, name: "Alice", age: 25, email: "alice@example.com", city: "New York" },
{ _id: 2, name: "Bob", age: 30, email: "bob@example.com", city: "Los Angeles" },
{ _id: 3, name: "Carol", age: 25, email: "carol@example.com", city: "Chicago" },
{ _id: 4, name: "Dave", age: 28, email: "dave@example.com", city: "New York" }
])
Code:
db.users.find({ age: 25 })
Result:
{ "_id" : 1, "name" : "Alice", "age" : 25, "email" : "alice@example.com", "city" : "New York" }
{ "_id" : 3, "name" : "Carol", "age" : 25, "email" : "carol@example.com", "city" : "Chicago" }
Example with Projection: Retrieve users aged 25, but only show their names and emails
Code:
db.users.find(
{ age: 25 },
{ name: 1, email: 1, _id: 0 }
)
Result:
{ "name" : "Alice", "email" : "alice@example.com" }
{ "name" : "Carol", "email" : "carol@example.com" }
count
method returns the number of documents that match a query.count
is db.collection.countDocuments(query)
.Example: Count the number of users aged 25
Code:
db.users.countDocuments({ age: 25 })
Result:
2
distinct
method finds the unique values for a specified field across a collection.distinct
is db.collection.distinct(field, query)
.Example: Get a list of unique cities where users aged 25 live
Code:
db.users.distinct("city", { age: 25 })
Result:
[ "New York", "Chicago" ]
Syntax:
db.collection.aggregate(pipeline, options)
pipeline
is an array of stages that process and transform the data.Example: Group users by city and count the number of users in each city
Sample Data:
Using the same users
collection as before.
Code:
db.users.aggregate([
{ $group: { _id: "$city", count: { $sum: 1 } } }
])
Result:
{ "_id" : "New York", "count" : 2 }
{ "_id" : "Los Angeles", "count" : 1 }
{ "_id" : "Chicago", "count" : 1 }
$group
stage groups documents by the specified _id
expression.$sum: 1
increments the count by 1 for each document in the group.Example: Calculate the average age of users in each city
Code:
db.users.aggregate([
{ $group: { _id: "$city", averageAge: { $avg: "$age" } } }
])
Result:
{ "_id" : "New York", "averageAge" : 26.5 }
{ "_id" : "Los Angeles", "averageAge" : 30 }
{ "_id" : "Chicago", "averageAge" : 25 }
MongoDB supports text search through text indexes, allowing you to perform search operations on string content.
Sample Data in articles
Collection:
db.articles.insertMany([
{ _id: 1, title: "Introduction to MongoDB", content: "MongoDB is a NoSQL database." },
{ _id: 2, title: "NoSQL Databases", content: "NoSQL databases are non-relational." },
{ _id: 3, title: "Relational Databases", content: "SQL databases are relational." },
{ _id: 4, title: "Advantages of NoSQL", content: "NoSQL databases like MongoDB are scalable." }
])
Creating a Text Index:
db.articles.createIndex({ content: "text" })
The syntax for text search is db.collection.find({ $text: { $search: searchString } })
.
Example: Find articles that contain the word "NoSQL"
Code:
db.articles.find({ $text: { $search: "NoSQL" } })
Result:
{ "_id" : 1, "title" : "Introduction to MongoDB", "content" : "MongoDB is a NoSQL database." }
{ "_id" : 2, "title" : "NoSQL Databases", "content" : "NoSQL databases are non-relational." }
{ "_id" : 4, "title" : "Advantages of NoSQL", "content" : "NoSQL databases like MongoDB are scalable." }
Advanced Text Search:
For phrase search, enclose the phrase in double quotes.
Example: Find articles containing the phrase "NoSQL databases"
Code:
db.articles.find({ $text: { $search: "\"NoSQL databases\"" } })
Result:
{ "_id" : 2, "title" : "NoSQL Databases", "content" : "NoSQL databases are non-relational." }
{ "_id" : 4, "title" : "Advantages of NoSQL", "content" : "NoSQL databases like MongoDB are scalable." }
To exclude terms, use a minus sign before the word.
Example: Find articles that contain "NoSQL" but not "MongoDB"
Code:
db.articles.find({ $text: { $search: "NoSQL -MongoDB" } })
Result:
{ "_id" : 2, "title" : "NoSQL Databases", "content" : "NoSQL databases are non-relational." }
Storing Location Data:
Sample Data in places
Collection:
db.places.insertMany([
{
_id: 1,
name: "Central Park",
location: {
type: "Point",
coordinates: [-73.9667, 40.78]
}
},
{
_id: 2,
name: "Times Square",
location: {
type: "Point",
coordinates: [-73.9855, 40.7580]
}
},
{
_id: 3,
name: "Empire State Building",
location: {
type: "Point",
coordinates: [-73.9857, 40.7484]
}
}
])
Creating a 2dsphere Index:
db.places.createIndex({ location: "2dsphere" })
The syntax for geospatial queries is:
db.collection.find({
location: {
$near: {
$geometry: point,
$maxDistance: distance
}
}
})
Example: Find places within 1,000 meters of Times Square
Code:
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.9855, 40.7580]
},
$maxDistance: 1000 // distance in meters
}
}
})
Result:
Assuming that the Empire State Building is within 1,000 meters of Times Square:
{ "_id" : 2, "name" : "Times Square", "location" : { "type" : "Point", "coordinates" : [ -73.9855, 40.758 ] } }
{ "_id" : 3, "name" : "Empire State Building", "location" : { "type" : "Point", "coordinates" : [ -73.9857, 40.7484 ] } }
$near
operator finds documents near a specified point.$geometry
field defines the point with coordinates.$maxDistance
sets the maximum distance from the point in meters.db.collection.createIndex(keys, options)
, where keys
specifies the field or fields to index.Example: Create an index on the age
field
db.users.createIndex({ age: 1 })
Use 1
for ascending order and -1
for descending order.
Compound Indexes:
Indexes can be created on multiple fields, known as compound indexes.
db.users.createIndex({ age: 1, city: 1 })
Use the explain()
method to understand how MongoDB executes a query and whether it utilizes an index.
db.users.find({ age: 25 }).explain("executionStats")
"stage": "IXSCAN"
to confirm index usage."nReturned"
and "totalKeysExamined"
for insights into query performance.Monitoring Indexes:
Use db.collection.getIndexes()
to list all indexes on a collection.
db.users.getIndexes()
Dropping Indexes:
Remove unnecessary indexes to optimize performance and reduce storage overhead.
db.users.dropIndex("age_1")