Integrar MongoDB con Python usando PyMongo

I

Introducción

En esta publicación, nos sumergiremos en MongoDB como almacén de datos desde una perspectiva de Python. Con ese fin, escribiremos un guión simple para mostrar lo que podemos lograr y los beneficios que podemos obtener de ello.

Las aplicaciones web, como muchas otras aplicaciones de software, funcionan con datos. La organización y el almacenamiento de estos datos son importantes, ya que dictan cómo interactuamos con las diversas aplicaciones a nuestra disposición. El tipo de datos que se manejan también puede influir en cómo llevamos a cabo este proceso.

Las bases de datos nos permiten organizar y almacenar estos datos, al mismo tiempo que controlamos cómo almacenamos, accedemos y protegemos la información.

Bases de datos NoSQL

Hay dos tipos principales de bases de datos: bases de datos relacionales y no relacionales.

Las bases de datos relacionales nos permiten almacenar, acceder y manipular datos en relación con otra pieza de datos en la base de datos. Los datos se almacenan en tablas organizadas con filas y columnas con relaciones que vinculan la información entre tablas. Para trabajar con estas bases de datos, utilizamos el lenguaje de consulta estructurado (SQL) y los ejemplos incluyen MySQL y PostgreSQL.

Las bases de datos no relacionales no almacenan datos en relación ni tabular, como en las bases de datos relacionales. También se conocen como bases de datos NoSQL ya que no usamos SQL para interactuar con ellas.

Además, las bases de datos NoSQL se pueden dividir en almacenes de valores clave, almacenes de gráficos, almacenes de columnas y almacenes de documentos, a los que pertenece MongoDB.

MongoDB y cuándo usarlo

MongoDB es un almacén de documentos y una base de datos no relacional. Nos permite almacenar datos en colecciones que se componen de documentos.

En MongoDB, un documento es simplemente un formato de serialización binario similar a JSON denominado BSONo Binary-JSON, y tiene un tamaño máximo de 16 megabytes. Este límite de tamaño está establecido para garantizar un uso eficiente de la memoria y el ancho de banda durante la transmisión.

MongoDB también proporciona Especificación GridFS en caso de que sea necesario almacenar archivos que superen el límite establecido.

Los documentos se componen de pares de valor de campo, al igual que en los datos JSON normales. Sin embargo, este formato BSON también puede contener más tipos de datos, como Date tipos y Binary Data tipos. BSON fue diseñado para ser liviano, fácilmente transitable y eficiente al codificar y decodificar datos hacia y desde BSON.

Al ser un almacén de datos NoSQL, MongoDB nos permite disfrutar de las ventajas que conlleva el uso de una base de datos no relacional sobre una relacional. Una ventaja es que ofrece una alta escalabilidad al escalar horizontalmente de manera eficiente mediante la fragmentación o la partición de los datos y colocarlos en varias máquinas.

MongoDB también nos permite almacenar grandes volúmenes de datos estructurados, semiestructurados y no estructurados sin tener que mantener relaciones entre ellos. Al ser de código abierto, el costo de implementación de MongoDB se mantiene bajo solo por mantenimiento y experiencia.

Como cualquier otra solución, existen desventajas al usar MongoDB. El primero es que no mantiene relaciones entre los datos almacenados. Debido a esto, es difícil de realizar Transacciones ACID que aseguran la coherencia.

La complejidad aumenta cuando se intenta admitir transacciones ACID. MongoDB, como otros almacenes de datos NoSQL, no es tan maduro como las bases de datos relacionales y esto puede dificultar la búsqueda de expertos.

La naturaleza no relacional de MongoDB lo hace ideal para el almacenamiento de datos en situaciones específicas sobre sus contrapartes relacionales. Por ejemplo, un escenario en el que MongoDB es más adecuado que una base de datos relacional es cuando el formato de datos es flexible y no tiene relaciones.

Con datos flexibles / no relacionales, no necesitamos mantener las propiedades ACID al almacenar datos en lugar de bases de datos relacionales. MongoDB también nos permite escalar fácilmente los datos a nuevos nodes.

Sin embargo, con todas sus ventajas, MongoDB no es ideal cuando nuestros datos son de naturaleza relacional. Por ejemplo, si almacenamos registros de clientes y sus pedidos.

En esta situación, necesitaremos una base de datos relacional para mantener las relaciones entre nuestros datos, que son importantes. Tampoco es adecuado utilizar MongoDB si necesitamos cumplir con las propiedades de ACID.

Interactuar con MongoDB a través de Mongo Shell

Para trabajar con MongoDB, necesitaremos instalar MongoDB Server, que podemos descargar desde el página de inicio oficial. Para esta demostración, usaremos el servidor de comunidades gratuito.

El servidor MongoDB viene con un Shell de Mongo que podemos utilizar para interactuar con el servidor a través del terminal.

Para activar el shell, simplemente escriba mongo en tu terminal. Recibirá información sobre la configuración del servidor MongoDB, incluida la versión MongoDB y Mongo Shell, junto con la URL del servidor.

Por ejemplo, nuestro servidor se ejecuta en:

mongodb://127.0.0.1:27017

En MongoDB, se utiliza una base de datos para almacenar colecciones que contienen documentos. A través del shell de Mongo, podemos crear una nueva base de datos o cambiar a una existente usando el use mando:

> use SeriesDB

Cada operación que ejecutemos después de esto se efectuará en nuestro SeriesDB base de datos. En la base de datos almacenaremos colecciones, que son similares a tablas en bases de datos relacionales.

Por ejemplo, para los propósitos de este tutorial, agreguemos algunas series a la base de datos:

> db.series.insertMany([
... { name: "Game of Thrones", year: 2012},
... { name: "House of Cards", year: 2013 },
... { name: "Suits", year: 2011}
... ])

Somos recibidos con:

{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("5e300724c013a3b1a742c3b9"),
        ObjectId("5e300724c013a3b1a742c3ba"),
        ObjectId("5e300724c013a3b1a742c3bb")
    ]
}

Para recuperar todos los documentos almacenados en nuestro series colección, usamos db.inventory.find({}), cuyo equivalente SQL es SELECT * FROM series. Pasar una consulta vacía (es decir {}) devolverá todos los documentos:

> db.series.find({})

{ "_id" : ObjectId("5e3006258c33209a674d1d1e"), "name" : "The Blacklist", "year" : 2013 }
{ "_id" : ObjectId("5e300724c013a3b1a742c3b9"), "name" : "Game of Thrones", "year" : 2012 }
{ "_id" : ObjectId("5e300724c013a3b1a742c3ba"), "name" : "House of Cards", "year" : 2013 }
{ "_id" : ObjectId("5e300724c013a3b1a742c3bb"), "name" : "Suits", "year" : 2011 }

También podemos consultar datos usando la condición de igualdad, por ejemplo, para devolver todas las series de TV que se estrenaron en 2013:

> db.series.find({ year: 2013 })
{ "_id" : ObjectId("5e3006258c33209a674d1d1e"), "name" : "The Blacklist", "year" : 2013 }
{ "_id" : ObjectId("5e300724c013a3b1a742c3ba"), "name" : "House of Cards", "year" : 2013 }

El equivalente de SQL sería SELECT * FROM series WHERE year=2013.

MongoDB también nos permite actualizar documentos individuales usando db.collection.UpdateOne()o realizar actualizaciones por lotes utilizando db.collection.UpdateMany(). Por ejemplo, para actualizar el año de lanzamiento de Suits:

> db.series.updateOne(
{ name: "Suits" },
{
    $set: { year: 2010 }
}
)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

Finalmente, para eliminar documentos, Mongo Shell ofrece la db.collection.deleteOne() y db.collection.deleteMany() funciones.

Por ejemplo, para eliminar todas las series que se estrenaron en 2012, correríamos:

> db.series.deleteMany({ year: 2012 })
{ "acknowledged" : true, "deletedCount" : 2 }

Puede encontrar más información sobre las operaciones CRUD en MongoDB en la referencia en línea incluyendo más ejemplos, realización de operaciones con condiciones, atomicidad y mapeo de conceptos SQL con conceptos y terminología de MongoDB.

Integrando Python con MongoDB

MongoDB proporciona controladores y herramientas para interactuar con un almacén de datos de MongoDB utilizando varios lenguajes de programación, incluidos Python, JavaScript, Java, Go y C #, entre otros.

PyMongo es el controlador oficial de MongoDB para Python, y lo usaremos para crear un script simple que usaremos para manipular los datos almacenados en nuestro SeriesDB base de datos.

Con Python 3.6+ y Virtualenv instalado en nuestras máquinas, vamos a crear un entorno virtual para nuestra aplicación e instalar PyMongo a través de pip:

$ virtualenv --python=python3 env --no-site-packages
$ source env/bin/activate
$ pip install pymongo

Utilizando PyMongo, vamos a escribir un script simple que podemos ejecutar para realizar diferentes operaciones en nuestra base de datos MongoDB.

Conexión a MongoDB

Primero, importamos pymongo en nuestro mongo_db_script.py y cree un cliente conectado a nuestra instancia de MongoDB que se ejecuta localmente:

import pymongo

# Create the client
client = MongoClient('localhost', 27017)

# Connect to our database
db = client['SeriesDB']

# Fetch our series collection
series_collection = db['series']

Hasta ahora, hemos creado un cliente que se conecta a nuestro servidor MongoDB y lo usamos para buscar nuestra base de datos ‘SeriesDB’. Luego buscamos nuestra colección ‘serie’ y la almacenamos en un objeto.

Crear documentos

Para hacer nuestro script más conveniente, escribiremos funciones que envuelvan PyMongo para permitirnos manipular datos fácilmente. Usaremos diccionarios de Python para representar documentos y pasaremos estos diccionarios a nuestras funciones. Primero, creemos una función para insertar datos en nuestra colección de ‘series’:

# Imports truncated for brevity

def insert_document(collection, data):
    """ Function to insert a document into a collection and
    return the document's id.
    """
    return collection.insert_one(data).inserted_id

Esta función recibe una colección y un diccionario de datos e inserta los datos en la colección proporcionada. Luego, la función devuelve un identificador que podemos usar para consultar con precisión el objeto individual de la base de datos.

También debemos tener en cuenta que MongoDB agrega un adicional _id clave de nuestros documentos, cuando no se facilitan, al momento de crear los datos.

Ahora intentemos agregar un programa usando nuestra función:

new_show = {
    "name": "FRIENDS",
    "year": 1994
}
print(insert_document(series_collection, new_show))

La salida es:

5e4465cfdcbbdc68a6df233f

Cuando ejecutamos nuestro script, el _id de nuestro nuevo programa está impreso en la terminal y podemos usar este identificador para buscar el programa más adelante.

Podemos proporcionar un _id valor en lugar de tenerlo asignado automáticamente, que proporcionaríamos en el diccionario:

new_show = {
    "_id": "1",
    "name": "FRIENDS",
    "year": 1994
}

Y si intentáramos almacenar un documento con un _id, recibiríamos un error similar al siguiente:

DuplicateKeyError: E11000 duplicate key error index: SeriesDB.series.$id dup key: { : 1}

Recuperando documentos

Para recuperar documentos de la base de datos usaremos find_document(), que consulta nuestra colección para documentos únicos o múltiples. Nuestra función recibirá un diccionario que contiene los elementos por los que queremos filtrar y un argumento opcional para especificar si queremos un documento o varios documentos:

# Imports and previous code truncated for brevity

def find_document(collection, elements, multiple=False):
    """ Function to retrieve single or multiple documents from a provided
    Collection using a dictionary containing a document's elements.
    """
    if multiple:
        results = collection.find(elements)
        return [r for r in results]
    else:
        return collection.find_one(elements)

Y ahora, usemos esta función para encontrar algunos documentos:

result = find_document(series_collection, {'name': 'FRIENDS'})
print(result)

Al ejecutar nuestra función, no proporcionamos la multiple parámetro y el resultado es un solo documento:

{'_id': ObjectId('5e3031440597a8b07d2f4111'), 'name': 'FRIENDS', 'year': 1994}

Cuando el multiple se proporciona el parámetro, el resultado es una lista de todos los documentos de nuestra colección que tienen un name atributo establecido en FRIENDS.

Actualización de documentos

Nuestra próxima función, update_document(), se utilizará para actualizar un único documento específico. Usaremos el _id del documento y la colección a la que pertenece al localizarlo:

# Imports and previous code truncated for brevity

def update_document(collection, query_elements, new_values):
    """ Function to update a single document in a collection.
    """
    collection.update_one(query_elements, {'$set': new_values})

Ahora, insertemos un documento:

new_show = {
    "name": "FRIENDS",
    "year": 1995
}
id_ = insert_document(series_collection, new_show)

Una vez hecho esto, actualice el documento, que especificaremos usando el _id regresó de agregarlo:

update_document(series_collection, {'_id': id_}, {'name': 'F.R.I.E.N.D.S'})

Y finalmente, vayamos a buscarlo para verificar que se ha establecido el nuevo valor e imprimamos el resultado:

result = find_document(series_collection, {'_id': id_})
print(result)

Cuando ejecutamos nuestro script, podemos ver que nuestro documento se ha actualizado:

{'_id': ObjectId('5e30378e96729abc101e3997'), 'name': 'F.R.I.E.N.D.S', 'year': 1995}

Eliminar documentos

Y finalmente, escriba una función para eliminar documentos:

# Imports and previous code truncated for brevity

def delete_document(collection, query):
    """ Function to delete a single document from a collection.
    """
    collection.delete_one(query)

Dado que estamos usando el delete_one , solo se puede eliminar un documento por llamada, incluso si la consulta coincide con varios documentos.

Ahora, usemos la función para eliminar una entrada:

delete_document(series_collection, {'_id': id_})

Si intentamos recuperar ese mismo documento:

result = find_document(series_collection, {'_id': id_})
print(result)

Nos reciben con el resultado esperado:

None

Próximos pasos

Hemos destacado y utilizado algunos de PyMongode interactuar con nuestro servidor MongoDB desde un script de Python. Sin embargo, no hemos utilizado todos los métodos disponibles a través del módulo.

Todos los métodos disponibles se pueden encontrar en el documentación oficial de PyMongo y se clasifican según los submódulos.

Hemos escrito un script simple que realiza una funcionalidad CRUD rudimentaria en una base de datos MongoDB. Si bien podríamos importar las funciones en una base de código más compleja, o en una aplicación Flask / Django, por ejemplo, estos marcos tienen bibliotecas para lograr los mismos resultados. Estas bibliotecas lo hacen más fácil, más conveniente y nos ayudan a conectarnos de manera más segura a MongoDB.

Por ejemplo, con Django podemos usar bibliotecas como Motor Django MongoDB y Djongo, mientras que Flask tiene Matraz-PyMongo que ayuda a cerrar la brecha entre Flask y PyMongo para facilitar una conectividad perfecta a una base de datos MongoDB.

Conclusión

MongoDB es un almacén de documentos y pertenece a la categoría de bases de datos no relacionales (NoSQL). Tiene ciertas ventajas en comparación con las bases de datos relacionales, así como algunas desventajas.

Si bien no es adecuado para todas las situaciones, aún podemos usar MongoDB para almacenar datos y manipular los datos de nuestras aplicaciones Python usando PyMongo entre otras bibliotecas, lo que nos permite aprovechar el poder de MongoDB en situaciones en las que es más adecuado.

Por lo tanto, depende de nosotros examinar cuidadosamente nuestros requisitos antes de tomar la decisión de utilizar MongoDB para almacenar datos.

El guión que hemos escrito en esta publicación se puede encontrar en GitHub.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad