Elixir and MongoDB

If you want to use the MongoDB in your next Killer-App-Project, but you did not dare ask because otherwise many would advise you to use Postgres, then you are right here. I won’t talk about choosing the right database. I will show how to use the MongoDB with Elixir. I assume that you already know the MongoDB and can use the Mongo Shell.

The first starting point are the official documentation pages of the driver. You can choose between two drivers:

I will add some more examples. But for now I published two simple crud examples to get an idea how to use the MongoDB driver. It is very simple.

In the example we just create, read, update and delete the following document:

def create_vcard() do
	%{
		firstname: "Alexander",
		lastname: "Abendroth",
		contact: %{
			email: "alexander.abendroth@campany.de",
			telephone: "+49 111938947373",
			mobile: "+49 222192938383",
			fax: "+49 3332929292"
		},
		addess: %{
			street: "Fasanenweg 5",
			postal_code: "12345",
			city: "Berlin",
			country: "de"
		}
	}
end

And here is our first CRUD example:

def example_1() do

	{:ok, top} = Mongo.start_link(url: "mongodb://localhost:27017/db-1")
	
	result = Mongo.insert_one(top, "people", create_vcard())

	IO.puts "#{inspect result}\n"

	result = Mongo.find_one(top, "people", %{})
	IO.puts "#{inspect result}\n"

	result = Mongo.update_one(top, "people", %{lastname: "Abendroth"}, ["$set": ["address.postal_code": "20000"]])
	IO.puts "#{inspect result}\n"

	result = Mongo.find_one(top, "people", %{"contact.email": "alexander.abendroth@campany.de"})
	IO.puts "#{inspect result}\n"

	result = Mongo.delete_one(top, "people", %{lastname: "Abendroth"})
	IO.puts "#{inspect result}\n"

end

We create a connection to the MongoDB-Instance listening von port 27001 and use the db-1

  1. We insert the document and get a result the ID: {:ok, %Mongo.InsertOneResult{acknowledged: true, inserted_id: #BSON.ObjectId<5d526a8f306a5f10851a0134>}}

  2. We are searching for the first document and got the inserted document back: %{"_id" => #BSON.ObjectId<5d526a8f306a5f10851a0134>, "addess" => %{"city" => "Berlin", "country" => "de", "postal_code" => "12345", "street" => "Fasanenweg 5"}, "contact" => %{"email" => "alexander.abendroth@campany.de", "fax" => "+49 3332929292", "mobile" => "+49 222192938383", "telephone" => "+49 111938947373"}, "firstname" => "Alexander", "lastname" => "Abendroth"}

  3. We update the postal code: {:ok, %Mongo.UpdateResult{acknowledged: true, matched_count: 1, modified_count: 1, upserted_ids: []}}

  4. We search again but search for the email: %{"_id" => #BSON.ObjectId<5d526a8f306a5f10851a0134>, "addess" => %{"city" => "Berlin", "country" => "de", "postal_code" => "12345", "street" => "Fasanenweg 5"}, "address" => %{"postal_code" => "20000"}, "contact" => %{"email" => "alexander.abendroth@campany.de", "fax" => "+49 3332929292", "mobile" => "+49 222192938383", "telephone" => "+49 111938947373"}, "firstname" => "Alexander", "lastname" => "Abendroth"}

  5. We delete the document: {:ok, %Mongo.DeleteResult{acknowledged: true, deleted_count: 1}}

The mongodb driver has the following features:

  • Supports MongoDB versions 3.2, 3.4, 3.6, 4.0
  • Connection pooling (through DBConnection 2.x)
  • Streaming cursors
  • Aggregation pipeline
  • Replica sets
  • Support for SCRAM-SHA-256 (MongoDB 4.x)
  • Support for change streams api (See)
  • Support for bulk writes (See)

I will try to add some more examples which show a special feature or how to the driver for some interesting use cases. But be patient I do this in my free time :slight_smile:

8 Likes

Any reason why this is better than existing drivers like this one? I mean that this is great project, but what was lacking in others and why not expand existing drivers instead of creating new one?

3 Likes

Look here:

1 Like

And mongodb? You have said you have forked that one, but there is no rationale why you needed to fork at all.

1 Like

Do I need some reasons to fork? Maybe I am too old, maybe I am too foolish. But I did it, because I want it! That is the main reason :kissing_heart:

No, you do not need reason, but I like to use Ockham’s razor, and when I can contribute to the core project without complete rewrite then I prefer to do so. That is why I am asking what your library does better (which is always good reason to fork), because I could miss something.

1 Like

I added a new example: change streams

If you set up a replica set then you can watch changes to the database or to collection without any other tools or frameworks. In this example I use a GenServer to observe changes to a collection.

Hi, I’m trying to do some aggregation with this adapter.

I’m tring to translate this mongo query:

db.trip.aggregate([{$group: {_id : "$city.name", count: {$sum: 1}}}])

That actually works in mongo shell and bring this results:

{ “_id” : { “name” : “City1” }, “count” : 212 }

{ “_id” : { “name” : “City2” }, “count” : 1200 }

{ “_id” : { “name” : “City3” }, “count” : 789 }

{ “_id” : { “name” : “City4” }, “count” : 540 }

{ “_id” : { “name” : “City5” }, “count” : 333 }

I’m tryin’ to use Mongo.aggregate but I don’t have clear the sintax, could anyone help me with this?

Thanks in advance.

This should work, but I have not tested it:

{:ok, top} = Mongo.start_link(url: "mongodb://localhost:27017/your-db")
pipeline = [%{"$group" => %{"_id" => "$city.name", "count" => %{"$sum" => 1}}}] 
Mongo.aggregate(top, "trip", pipeline)

Thanks for this. But what do you need to do to get it to run?
I’m on Elixir 1.11.1. My mix.exs has

  defp deps do
    [
      {:gettext, "~> 0.11"},
      {:mongodb_driver, "~> 0.7.0"},
      {:mongodb, "~> 0.5.1"}
    ]
  end

and my app is start.exs:

#! /usr/bin/env elixir

defmodule MongoExample do
  def example1() do

    {:ok, conn} = Mongo.start_link(url: "mongodb://localhost:27017/db-1")
    cursor = Mongo.find(conn, "test-collection", %{})

    cursor
    |> Enum.to_list()
    |> IO.inspect
  end
end 

MongoExample.example1()

Mongo is running, but when I run the app, I just get “Mongo.start_link/1 is undefined (module Mongo is not available)”

I figured out how to make MongoDB work with Elixir/Phoenix. A simple example can be found here: https://github.com/pdxrod/simple_mongo_app.

1 Like