Getting started with MongoDB and Eiffel

in eiffel •  7 years ago  (edited)

Getting started with MongoDB and Eiffel

N|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. DB 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:

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

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.get_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.

        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.get_database_names (Void) 
        across l_database_names as ic loop print (ic.item + "%N")  end
    end

Create a Collection

Now, we will show you how to create a Collection (table equivalent to MongoDB) for our database.
Firs,t we need to connect to our database as follow

        -- Initialize and create a new mongobd client instance.
    create l_client.make ("mongodb://127.0.0.1:27017")
                -- Accessing a database
    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")  end

There 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.get_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 iterates through the result cursors and prints 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.get_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 feature update_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.get_collection ("mydb", "mycoll")
                -- First we create a document
            create l_oid.make (Void)
            create l_doc.make
            l_doc.bson_append_oid ("_id", l_oid)
            l_doc.bson_append_utf8 ("key", "Hello Eiffel")
            create l_error.default_create
            l_collection.insert_one (l_doc,Void, Void, l_error)

                             - - Update the document we just create 
            create l_query.make
            l_query.bson_append_oid ("_id", l_oid)
            create l_subdoc.make
            l_subdoc.bson_append_utf8 ("key", "Hello MongoDB from Eiffel")
            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.get_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=delete-example")
            l_collection := l_client.get_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

Conclusion

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

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!