Repository: opsdroid/opsdroid

Issue:
Move MongoDB database module into core
This issue covers adding the [MongoDB database module](https://github.com/opsdroid/database-mongo) to core.

## Background
A while ago we began moving connectors and databases from external plugins into the core of the project (see #185 for more context). We started with [slack](https://github.com/opsdroid/opsdroid/blob/master/opsdroid/connector/slack/__init__.py) and [websockets](https://github.com/opsdroid/opsdroid/blob/master/opsdroid/connector/websocket/__init__.py) connectors but need to go through all the other existing plugins and move them into the core.

## Steps

 - Make a new submodule directory in [`opsdroid.database`](https://github.com/opsdroid/opsdroid/tree/master/opsdroid/database) and copy the database code over.
 - Update the [`requirements.txt`](https://github.com/opsdroid/opsdroid/blob/master/requirements.txt) with any dependencies from the database if necessary.
 - Write tests for the database. (See the [Slack connector tests](https://github.com/jacobtomlinson/opsdroid/blob/master/tests/test_connector_slack.py) for inspiration).
 - Copy the relevant information from the database `README.md` into a [new documentation page](https://github.com/opsdroid/opsdroid/tree/master/docs/connectors).
 - Add the new page to the [mkdocs.yml](https://github.com/opsdroid/opsdroid/blob/master/mkdocs.yml).
 - Add to the [list of databases](https://github.com/opsdroid/opsdroid/blob/master/docs/configuration-reference.md#database-modules).
 - Add a deprecation notice to the old database module. (See [the slack connector](https://github.com/opsdroid/connector-slack))


Discussion:
Hi may i  work on this issue? I'm new to opensource.

Resolving patch:
diff --git a/opsdroid/database/mongo/__init__.py b/opsdroid/database/mongo/__init__.py
new file mode 100644
--- /dev/null
+++ b/opsdroid/database/mongo/__init__.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+"""A module for opsdroid to allow persist in mongo database."""
+import logging
+from motor.motor_asyncio import AsyncIOMotorClient
+
+from opsdroid.database import Database
+
+
+class DatabaseMongo(Database):
+    """A module for opsdroid to allow memory to persist in a mongo database.
+
+    Attributes:
+
+    """
+
+    def __init__(self, config):
+        """Create the connection.
+
+        Set some basic properties from the database config such as the name
+        of this database.
+
+        Args:
+            config (dict): The config for this database specified in the
+                           `configuration.yaml` file.
+
+        """
+        super().__init__(config)
+        logging.debug("Loaded mongo database connector")
+        self.name = "mongo"
+        self.config = config
+        self.client = None
+        self.database = None
+
+    async def connect(self, opsdroid):
+        """Connect to the database.
+
+        Args:
+            obsdroid (object): the opsdroid instance
+        """
+        host = self.config["host"] if "host" in self.config else "localhost"
+        port = self.config["port"] if "port" in self.config else "27017"
+        database = self.config["database"] \
+            if "database" in self.config else "opsdroid"
+        path = "mongodb://" + host + ":" + port
+        self.client = AsyncIOMotorClient(path)
+        self.database = self.client[database]
+        logging.info("Connected to mongo")
+
+    async def put(self, key, data):
+        """Insert or replace an object into the database for a given key.
+
+        Args:
+            key (str): the key is the databasename
+            data (object): the data to be inserted or replaced
+        """
+        logging.debug("Putting %s into mongo", key)
+        if "_id" in data:
+            await self.database[key].update_one({"_id": data["_id"]},
+                                                {"$set": data})
+        else:
+            await self.database[key].insert_one(data)
+
+    async def get(self, key):
+        """Get a document from the database (key).
+
+        Args:
+            key (str): the key is the databasename.
+        """
+        logging.debug("Getting %s from mongo", key)
+        return await self.database[key].find_one(
+            {"$query": {}, "$orderby": {"$natural": -1}}
+            )


Test patch:
diff --git a/tests/mockmodules/databases/mongo/mongo_database.py b/tests/mockmodules/databases/mongo/mongo_database.py
new file mode 100644
--- /dev/null
+++ b/tests/mockmodules/databases/mongo/mongo_database.py
@@ -0,0 +1,33 @@
+"""A mocked database module."""
+
+from opsdroid.database.mongo import DatabaseMongo
+
+
+class DatabaseMongoTest():
+    """The mocked database mongo class."""
+
+    def __init__(self, config):
+        """Start the class."""
+        self.config = config
+        self.dummy_db = {}
+
+    async def find_one(self,key):
+        """Mock method find_one.
+
+        Args: key(object) not considered for test
+        """
+        return await self.dummy_db;
+
+    async def update_one(self,key,update):
+        """Mock method update_one.
+
+        Args: key(object) not considered for test
+        """
+        return await self.dummy_db;
+
+    async def insert_one(self,key):
+        """Mock method insert_one.
+
+        Args: key(object) not considered for test
+        """
+        return self.dummy_db;
diff --git a/tests/test_database_mongo.py b/tests/test_database_mongo.py
new file mode 100644
--- /dev/null
+++ b/tests/test_database_mongo.py
@@ -0,0 +1,71 @@
+"""Tests for the DatabaseMongo class. """
+
+import unittest
+import asynctest
+
+
+from opsdroid.database.mongo import DatabaseMongo
+from mockmodules.databases.mongo.mongo_database import DatabaseMongoTest
+
+class TestDatabaseMongoClass(unittest.TestCase):
+    """Test the opsdroid mongo database class."""
+
+    def test_init(self):
+        """Initialization fo mock database"""
+        config = {"example_item": "test"}
+        database = DatabaseMongo(config)
+        self.assertEqual("mongo", database.name)
+        self.assertEqual("test", database.config["example_item"])
+
+
+class TestDatabaseBaseMongoClassAsync(asynctest.TestCase):
+    """Test the opsdroid database base class."""
+
+    async def test_connect(self):
+        """test the method connect"""
+        database = DatabaseMongo({})
+        try:
+            await database.connect({})
+        except NotImplementedError:
+            raise Exception
+        else:
+            pass
+
+    async def test_get2(self):
+        """test of mocked method get"""
+        database = DatabaseMongo({})
+        database.database = {}
+        database.database['test'] = DatabaseMongoTest({})
+        try:
+            await database.get("test")
+        except TypeError:
+            pass
+        else:
+            raise Exception
+
+    async def test_put2(self):
+        """test of mocked method put"""
+        database = DatabaseMongo({})
+        try:
+            await database.put("test", {})
+        except TypeError:
+            pass
+        else:
+            raise Exception
+
+    async def test_put(self):
+        """test of mocked  put"""
+        database = DatabaseMongo({})
+        database.database = {}
+        database.database['test'] = DatabaseMongoTest({})
+        try:
+            await database.put("test", {"_id":"0" , "key":"value"})
+        except TypeError:
+            try:
+                await database.put("test", {})
+            except NotImplementedError:
+                raise Exception
+            else:
+                pass
+        else:
+            raise Exception