In the previous chapter, we discussed the pros and cons of SQL databases and some of their use cases. We’ll do the same for NoSQL databases using MongoDB as a database in this chapter.

Pros and Cons of NoSQL Databases

Pros

Cons

Easy to use: This could be a subjective point, but NoSQL databases (especially document ones) tend to be easier for beginners to set up and use.

Data inconsistency:  Not having a schema can also be tricky. This means that some corrupt data can get through if we don’t make sure to verify mandatory fields before saving.

Flexibility: This could be one of the reasons for the previous point. NoSQL databases don’t rely on a schema, so it’s easier to make changes to our data format, ensuring flexibility.

Indexing: This is trickier in NoSQL than in SQL databases, because NoSQL databases have limited indexing options.

Scalability: Horizontal scalability for MongoDB is really useful. It’s easy to configure and does exactly what it’s meant to do. The same applies to many other NoSQL databases.

Data duplication: When using document databases, we might end up with duplicated data, since the relation between entities is not very straightforward.

Use case

NoSQL databases are generally used for e-commerce. In cases like these, the product being sold might be very different, so having a common schema is not possible. But having a schema for each product is also not possible when there is a large variety of products.

Using NoSQL solves this issue; we don’t have to worry about the schema and we can save what we need. However, we should always define common mandatory fields (ID, price, etc.), so creating a parent type and using inheritance is necessary when working on bigger projects.

For our use case, we’ll use NoSQL to store our books, authors, and reviews.

Adding data

We can easily create collections and add data using the MongoDB Compass. If we want to use the Mongo shell (which can also be used via MongoDB Compass), then we can use the following commands:

  • Show available databases:

    show databases
    
  • Use database:

    use educative
    
  • Create a collection:

    db.createCollection("books")
    
  • Add a document:

    db.books.insertOne({"title":"Eloquent JavaScript, Third Edition","price":32.23,"identifier":"9781593279509","description":"JavaScript lies at the heart of almost every modern web application, from social apps like Twitter to browser-based game frameworks like Phaser and Babylon. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications.","authorId":"61dad1982e6de6ae05c72165","reviewIds":[]})
    
  • Since we use db.<collection_name>.insertOne, we can substitute insertOne with insertMany, updateOne, updateMany, deleteOne, deleteMany, and more. You can check the MongoDB documentation for more details.

Adding a dependency

There are a lot of different drivers to choose from, but we’ll work with the one from denodrivers for this example.

We need to import the client that we’ll use to establish the connection and execute queries:

import { Bson, MongoClient } from "https://deno.land/x/mongo/mod.ts";

We can use Bson to define an ObjectId, which is how MongoDB represents IDs.

Establishing a connection

After adding the import statement, we can now establish our database connection in three different ways, depending on the type of connection we want to establish:

Press + to interact
const client = new MongoClient();
// Connecting to a Local Database
await client.connect("mongodb://localhost:27017");
// Connecting to a Mongo Atlas Database
await client.connect({
db: "<db_name>",
tls: true,
servers: [
{
host: "<db_cluster_url>",
port: 27017,
},
],
credential: {
username: "<username>",
password: "<password>",
db: "<db_name>",
mechanism: "SCRAM-SHA-1",
},
});
// Connect using srv url
await client.connect(
"mongodb+srv://<username>:<password>@<db_cluster_url>/<db_name>?authMechanism=SCRAM-SHA-1",
);

Let’s take a look at what we’re doing in the code above:

  • Line 1: We create the MongoDB client.
  • Line 4: We connect to a local MongoDB instance, “(option 1)”.
  • Line 7-22: We connect to a Mongo Atlas database, “(option 2)”.
  • Line 25-27: We connect to a MongoDB instance using an SRV URL, “(option 3)”.

Running queries

In this section, we’ll learn how to access our MongoDB collections using Deno and run different queries on them. Let’s return to our book collection with basic fields to simplify this part.

This is what our schema looks like:

Press + to interact
const types = gql`
type Book {
_id: String
title: String
price: Float
identifier: String
description: String
author: Author
reviews: [Review]
}
input BookInput {
title: String
price: Float
identifier: String
description: String
}
`

Access the collection

To access our collection and manipulate data easily, let’s create an interface called BookSchema. This interface will be used by our Mongo client.

Press + to interact
// Defining schema interface
interface BookSchema {
_id: Bson.ObjectId;
title: string;
price: number;
identifier: string;
description: string;
}
// Access collections
const db = client.database("educative");
const books = db.collection<BookSchema>("books");

Now that we have access to our collection, we can perform all sorts of data operations, discussed below.

Insert data

To insert a new book via our addBook mutation, we can do the following:

Press + to interact
const resolvers = {
//.
//.
//.
Mutation: {
addBook: async (_parent: any, { input: { title, price, identifier, description } }: any, _context: any, _info: any) => {
console.log(`addBook() title=(${title}), price=(${price}), identifier=(${identifier}) description=(${description})`);
await books.insertOne({ title, price, identifier, description });
return {
done: true,
};
},
}
}

Fetch data

To get all the books in our database, we update the getAllBooks query as the To get all the books in our database, we update the getAllBooks query as follows::

Press + to interact
const resolvers = {
Query: {
getAllBooks: async () => {
return await books.find().toArray();
},
}
}

Other operations

We can also perform other operations using the Mongo library:

  • Update: We can update books using books.updateOne() and books.updateMany().
  • Replace: We can replace books using books.replaceOne().
  • Delete: We can delete books using books.deleteOne() and books.deleteMany().

Note: We’ll use some of these operations in the final version of our endpoint.