Last modified: December 03, 2024

This article is written in: 🇺🇸

Querying NoSQL Databases

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.

Introduction to MongoDB

Data Model

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"
    }
  ]
}

Query Language

Examples of Query Operators:

Basic Queries

Find

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

Example: Count the number of users aged 25

Code:

db.users.countDocuments({ age: 25 })

Result:

2

Distinct

Example: Get a list of unique cities where users aged 25 live

Code:

db.users.distinct("city", { age: 25 })

Result:

[ "New York", "Chicago" ]

Advanced Queries

Aggregation

Syntax:

db.collection.aggregate(pipeline, options)

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 }

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." }

Geospatial Queries

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 ] } }

Indexing in MongoDB

Creating Indexes

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 })

Types of Indexes

Index Usage

Use the explain() method to understand how MongoDB executes a query and whether it utilizes an index.

db.users.find({ age: 25 }).explain("executionStats")

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")

Table of Contents

    Querying NoSQL Databases
    1. Introduction to MongoDB
      1. Data Model
      2. Query Language
    2. Basic Queries
      1. Find
      2. Count
      3. Distinct
    3. Advanced Queries
      1. Aggregation
      2. Text Search
      3. Geospatial Queries
    4. Indexing in MongoDB
      1. Creating Indexes
    5. Types of Indexes
    6. Index Usage