Integrar MongoDB con Python usando PyMongo

    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.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *