Node.js MongoDB: Join Collections

Welcome to The Coding College! In this tutorial, we’ll explore how to perform a “join” operation in MongoDB using Node.js. Although MongoDB is a NoSQL database that doesn’t natively support joins like relational databases, you can achieve similar functionality using the $lookup aggregation stage.


Prerequisites

Before we begin, ensure you have the following:

  1. Node.js Installed: Download Node.js.
  2. MongoDB Installed: Install MongoDB.
  3. MongoDB Driver Installed: Run: npm install mongodb

Example Use Case

Suppose we have two collections:

  1. Users [ { "_id": 1, "name": "John Doe", "age": 28 }, { "_id": 2, "name": "Alice", "age": 25 } ]
  2. Orders [ { "orderId": 101, "userId": 1, "amount": 500 }, { "orderId": 102, "userId": 2, "amount": 300 }, { "orderId": 103, "userId": 1, "amount": 700 } ]

We want to join these collections to associate each user with their orders.


Step 1: Connect to MongoDB

Create a file named joinCollections.js and add the following code to connect to MongoDB:

const { MongoClient } = require('mongodb');

// MongoDB connection URL
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);

// Database Name
const dbName = 'myNewDatabase';

async function connectToDatabase() {
  try {
    await client.connect();
    console.log('Connected to MongoDB.');
    return client.db(dbName);
  } catch (err) {
    console.error('Database connection error:', err.message);
  }
}

Step 2: Perform the Join Using $lookup

The $lookup stage in MongoDB’s aggregation pipeline enables us to join collections.

Example: Join Users with Their Orders

async function joinCollections() {
  const db = await connectToDatabase();
  const usersCollection = db.collection('users');

  try {
    const joinedData = await usersCollection.aggregate([
      {
        $lookup: {
          from: 'orders',       // Collection to join
          localField: '_id',    // Field in the users collection
          foreignField: 'userId', // Field in the orders collection
          as: 'userOrders'      // Alias for the resulting array
        }
      }
    ]).toArray();

    console.log('Joined Data:', JSON.stringify(joinedData, null, 2));
  } catch (err) {
    console.error('Error during join operation:', err.message);
  } finally {
    await client.close();
  }
}

joinCollections();

Step 3: Example Output

Running the above code will produce a result like this:

[
  {
    "_id": 1,
    "name": "John Doe",
    "age": 28,
    "userOrders": [
      { "orderId": 101, "userId": 1, "amount": 500 },
      { "orderId": 103, "userId": 1, "amount": 700 }
    ]
  },
  {
    "_id": 2,
    "name": "Alice",
    "age": 25,
    "userOrders": [
      { "orderId": 102, "userId": 2, "amount": 300 }
    ]
  }
]

Step 4: Filtering Joined Data

You can add more stages to the pipeline to filter the joined data.

Example: Filter Users with Orders Above $500

async function joinAndFilter() {
  const db = await connectToDatabase();
  const usersCollection = db.collection('users');

  try {
    const filteredData = await usersCollection.aggregate([
      {
        $lookup: {
          from: 'orders',
          localField: '_id',
          foreignField: 'userId',
          as: 'userOrders'
        }
      },
      {
        $match: {
          'userOrders.amount': { $gt: 500 } // Filter criteria
        }
      }
    ]).toArray();

    console.log('Filtered Data:', JSON.stringify(filteredData, null, 2));
  } catch (err) {
    console.error('Error during join and filter operation:', err.message);
  } finally {
    await client.close();
  }
}

joinAndFilter();

Best Practices

  1. Indexing: Ensure the fields used in $lookup (e.g., localField and foreignField) are indexed for optimal performance.
  2. Pagination: Limit the size of the data returned using the $limit stage.
  3. Complex Joins: For more complex relationships, consider additional stages like $unwind and $project.
  4. Data Validation: Validate joined results to ensure data consistency.

Conclusion

MongoDB’s $lookup aggregation stage is a powerful way to join collections and simulate relational database joins. By combining $lookup with other stages like $match, $unwind, and $project, you can extract meaningful insights from your data.

For more tutorials and coding resources, visit The Coding College.

Happy coding! 🚀

Leave a Comment