Getting Started with MongoDB and Eiffel

by javier (modified: 2018 Jun 14)

Getting started with MongoDB and Eiffel

In this article, we’ll have a look at integrating MongoDB, a very popular NoSQL open source database with the MongoDB Eiffel Driver, at the moment under development.

MongoDB is written in C++ and has quite a number of solid features such as map-reduce, auto-sharding, replication, high availability etc, and it's the most popular NoSQL databases and it's one of the most used solutions including Relational Databases. Check theDB engine ranking.

What is MongoDB?

MongoDB is a NoSQL database where we can store data in BSON format where a key represents the property and the value represents the property value stored against a key. Below we describe a few key points about MongoDB itself:

  • stores data in BSON (JSON-like) documents that can have various structures.
  • uses dynamic schemas, which means that we can create records without predefining anything.
  • the structure of a record can be changed simply by adding new fields or deleting existing ones.

The above-mentioned data model gives us the ability to represent hierarchical relationships, to store arrays and other more complex structures easily.

Documents

In Mongo, the document represents a data structure that can hold any number of key and value pairs.

Collections

In Mongo, often, documents with the same structure are put into a bucket, called a collection. You can think of a collection as a table in a relational database, where every row represents a document.

No Schema

This is one of the key differences between a SQL and NoSQL database, it means it has no predefined schema — it can hold anything in BSON format.

Mapping Relational Databases Concepts to MongoDB

Understanding concepts in MongoDB become easier if we can compare them to relational database structures. Let’s see the analogies between Mongo and a traditional MySQL system:

  • A table in MySQL becomes a Collection in Mongo
  • Row becomes a Document
  • Column becomes a Field
  • Joins are defined as linking and embedded documents This is a simplistic way to look at the MongoDB core concepts of course, but nevertheless useful, to learn more check the following article

To learn more: - MongoDB Tutorials List of available MongoDB Tutorials part of MongoDB Manual.

Now, let’s dive into implementation to understand this powerful database.

Get the MongoDB Eiffel Driver

$ git clone https://github.com/jvelilla/mongo-eiffel-driver
$ cd mongo-eiffel-driver

The Driver has been tested on Windows and Linux using 64 bits.

Note: At the moment you will need to link the code using MongoDB dynamic library, so be sure to have in your PATH libbson-1.0.dll and libmongoc-1.0.dll. You can get them here https://github.com/jvelilla/mongo-eiffel-driver/tree/master/C/mongo-c-driver/bin (only Windows 64 bits).

Using MongoDB

Now, let’s start implementing Mongo queries with Eiffel. We will follow with the basic CRUD operations as they are the best to start with.

Make a Connection

l_client: MONGODB_CLIENT ... -- Initialize and create a new mongobd client instance. create l_client.make ("mongodb://127.0.0.1:27017")

Connecting to a Database

Now, let’s connect to our database. It is interesting to note that Databases are automatically created on the MongoDB server upon insertion of the first document into a collection. There is no need to create a database manually.

      When Mongo sees that database doesn’t exist, it will create it for us.

class APPLICATION create make feature {NONE} -- Initialization make -- Run application. local l_client: MONGODB_CLIENT l_database: MONGODB_DATABASE do -- Initialize and create a new mongobd client instance. create l_client.make ("mongodb://127.0.0.1:27017") print ("Connected to the database successfully%N") -- Accessing a database l_database := l_client.database ("newDB") -- Exists collection "newCollection"? if l_database.has_collection ("newCollection") then print ("Collection newCollection exists%N") else print ("Collection newCollection does not exists%N") end end end

Query Existing Databases

Show the existing list of known databases.

class APPLICATION create make feature {NONE} -- Initialization make -- Run application -- show the existing list of databases. local l_client: MONGODB_CLIENT l_database_names: LIST [STRING] do -- Initialize and create a new mongobd client instance. create l_client.make ("mongodb://127.0.0.1:27017") l_database_names := l_client.database_names (Void) print ("Databases%N") print ("=================%N") across l_database_names as ic loop print (ic.item + "%N") end end end

Create a Collection

Now, will show you how to create a Collection (table equivalent to MongoDB) for our database. First, we need to connect to our database as follow -- Initialize and create a new MongoDB client instance. create l_client.make ("mongodb://127.0.0.1:27017") l_database := l_client.get_database ("db_name")Now we can display the current collections in our database db_name

across l_database.get_collection_names (VOID) as ic loop print (ic.item + "%N") end

Once we have connected to our database, we can create our collection with the following code.

-- create a new collection using MONGODB_DATABASE l_collection := l_database.create_collection ("my_new_collection", Void) across l_database.get_collection_names (VOID) as ic loop print (ic.item + "%N") endThere is another option to create collections in MongoDB. In the previous example we create the collection manually, but we can create collections automatically upon insertion of the first document.

Basic CRUD Operations

This section demonstrates the basics of using the Eiffel Driver to interact with MongoDB.

Create a Document

To insert/create documents into a collection, first we obtain an object instance of MONGODB_COLLECTION via a MONGODB_CLIENT. Then, use the feature insert_one to add BSON documents to the collection. create_document local l_client: MONGODB_CLIENT l_collection: MONGODB_COLLECTION l_doc: BSON l_oid: BSON_OID l_error: BSON_ERROR do -- Create a new client instance. create l_client.make ("mongodb://localhost:27017/?appname=insert-example") -- Get a colletion using MONGODB_CLIENT.get_collection feature -- with database name and the collection name. l_collection := l_client.collection ("mydb", "mycoll") create l_doc.make create l_oid.make (Void) l_doc.bson_append_oid ("_id", l_oid) l_doc.bson_append_utf8 ("hello", "eiffel") create l_error l_collection.insert_one (l_doc, Void, Void, l_error) end The document will be inserted into a database named mydb under collection mycoll

{"_id":"5ac6d0689c990617c8007ef2","hello":"eiffel"} 

Read a Document

To read a document we need to query a MongoDB collection, using the feature find_with_opts. This returns a cursor MONGODB_CURSOR to the matching documents.

We will use the following document as an example

 {"hello":"eiffel"}

The following example iterate through the result cursors and print the matches to stdout as JSON strings.

read_document local l_client: MONGODB_CLIENT l_collection: MONGODB_COLLECTION l_query: BSON l_cursor: MONGODB_CURSOR l_after: BOOLEAN do create l_client.make ("mongodb://localhost:27017/?appname=find-example") l_collection := l_client.collection ("mydb", "mycoll") create l_query.make l_query.bson_append_utf8 ("hello", "eiffel") l_cursor := l_collection.find_with_opts (l_query, Void, Void) from until l_after loop if attached l_cursor.next as l_bson then print (l_bson.bson_as_canonical_extended_json) print ("%N") else l_after := True end end end

Update a Document

We will use the database mydb and we will insert a new document into the mycoll collection. Then using the BSON_ID we use in the previous insert will update it with a different value and a new field, calling the featureupdate_one

update_document local l_client: MONGODB_CLIENT l_collection: MONGODB_COLLECTION l_doc: BSON l_update: BSON l_query: BSON l_oid: BSON_OID l_error: BSON_ERROR l_subdoc: BSON do create l_client.make ("mongodb://localhost:27017/?appname=update-example") l_collection := l_client.collection ("mydb", "mycoll") create l_oid.make (Void) create l_doc.make l_doc.bson_append_oid ("_id", l_oid) l_doc.bson_append_utf8 ("key", "old_value") create l_error.default_create l_collection.insert_one (l_doc,Void, Void, l_error) create l_query.make l_query.bson_append_oid ("_id", l_oid) create l_subdoc.make l_subdoc.bson_append_utf8 ("key", "new_value") l_subdoc.bson_append_boolean ("updated", True) create l_update.make l_update.bson_append_document ("$set", l_subdoc) create l_error.default_create l_collection.update_one (l_query, l_update, Void, Void, l_error) end

Delete a Document

Here we will show you how to use the feature delete_one to delete a document. The following code inserts a sample document into the database mydb and collection mycoll. Then, it deletes all documents matching {"hello" : "world"}.

delete_document local l_client: MONGODB_CLIENT l_collection: MONGODB_COLLECTION l_doc: BSON l_oid: BSON_OID l_error: BSON_ERROR do create l_client.make ("mongodb://localhost:27017/?appname=delete-example") l_collection := l_client.collection ("test", "test") create l_oid.make (Void) create l_doc.make l_doc.bson_append_oid ("_id", l_oid) l_doc.bson_append_utf8 ("hello", "world") -- insert a document create l_error l_collection.insert_one (l_doc, Void, Void, l_error) -- delete the document. create l_doc.make l_doc.bson_append_oid ("_id", l_oid) create l_error l_collection.delete_one (l_doc, Void, Void, l_error) end

Count documents

Counting the number of documents in a MongoDB collection is similar to performing a find operation. This example counts the number of documents matching {"hello" : "world"} in the database mydb and collection mycoll.

count_documents local l_client: MONGODB_CLIENT l_doc: BSON l_collection: MONGODB_COLLECTION l_error: BSON_ERROR l_count: INTEGER_64 do create l_client.make ("mongodb://localhost:27017/?appname=count-example") l_collection := l_client.collection ("mydb", "mycoll") create l_doc.make l_doc.bson_append_utf8 ("hello", "world") create l_error l_count := l_collection.count ((create {MONGODB_QUERY_FLAG}).mongoc_query_none, l_doc, 0, 0, Void, l_error) if l_count < 0 then print ("Error message: " + l_error.message) else print ("Number of documents:" + l_count.out) end end

Find all documents

To find all documents from a collection will use the feature MONGODB_COLLECTION.find_with_opts using an empty query. This feature will return a MONGODB_CURSOR. In the example, we iterate it and print its document as a JSON string.

find_all_documents note local l_client: MONGODB_CLIENT l_collection: MONGODB_COLLECTION l_query: BSON l_cursor: MONGODB_CURSOR l_after: BOOLEAN do create l_client.make ("mongodb://localhost:27017/?appname=find-all-example") l_collection := l_client.collection ("mydb", "mycoll") create l_query.make l_cursor := l_collection.find_with_opts (l_query, Void, Void) from until l_after loop if attached l_cursor.next as l_bson then print (l_bson.bson_as_canonical_extended_json) print ("%N") else l_after := True end end end

Conclusion

This blog it's a quick introduction to Eiffel MongoDB driver tutorial based on the MongoDB-C driver. To get the code of all these examples got the GitHub repository.

On upcoming posts, I will show you how :

  • Build a REST API using EiffelWeb with MongoDB
  • Write a Web User Interface for our REST API
  • Deploy it ...