Using MongoDB with Deno
Learn when to use NoSQL with MongoDB.
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 substituteinsertOne
withinsertMany
,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:
const client = new MongoClient();// Connecting to a Local Databaseawait client.connect("mongodb://localhost:27017");// Connecting to a Mongo Atlas Databaseawait 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 urlawait 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:
const types = gql`type Book {_id: Stringtitle: Stringprice: Floatidentifier: Stringdescription: Stringauthor: Authorreviews: [Review]}input BookInput {title: Stringprice: Floatidentifier: Stringdescription: 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.
// Defining schema interfaceinterface BookSchema {_id: Bson.ObjectId;title: string;price: number;identifier: string;description: string;}// Access collectionsconst 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:
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::
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()
andbooks.updateMany()
. - Replace: We can replace books using
books.replaceOne()
. - Delete: We can delete books using
books.deleteOne()
andbooks.deleteMany()
.
Note: We’ll use some of these operations in the final version of our endpoint.