9

Cosas básicas de un CRUD en MongoDB

Enrique
edevars
18369

Un CRUD (Create,Read,Update,Delete) pueden ser las operaciones generales que puede realizar un sistema para el manejo de datos. Depende de el entorno de desarrollo puede variar la manera en la que se implementa.

En MongoDB es posible implementar estas funcionalidades a través de sus diferentes métodos, sin embargo primero es necesario conocer algunos comandos generales de la Mongo Shell una vez estemos conectados a nuestro cluster.

Mostrar base de datos

Este comando nos muestra todas las bases de datos que se han creado en nuestro cluster

show dbs

Crear base de datos o usar una ya existente

use database_name  

Cabe aclarar que MongoDB no crea bases de datos vacías, si se quiere que la base de datos se materialice se le debe de crear un documento.

Consultar ayuda sobre algún comando

Si queremos saber los métodos que podemos ejecutar sobre alguna entidad de mongo como lo puede ser la base de datos o las colecciones, debemos invocar al método help()

//Muestra todas las funciones que podemos hacer a la base de datos en uso
db.help()  
    
//Muestra todas las funciones que le podemos hacer a una colección
db.collectionName()

Crear documento dentro de una colección

Esto se pude realizar a través del comando insertOne() en la shell de mongo. Al momento de ejecutarlo el comando nos regresara si se creo o no el documento

db.collectionName.insertOne({ 
// Document in JSON format 
})
<h3>Ejemplo</h3>

En este caso insertamos un objeto JSON con ciertos atributos a la colección inventory

    db.inventory.insertOne({ 
      item:"canvas", 
      qty:100, 
      tags:["cotton"], 
      size: {
      h:28, 
      w:35.5, 
      uom:"cm"}
       })

La respuesta si se crea correctamente es un JSON con el siguiente formato

  {
    "acknowledged" : true,
	  "insertedId" : ObjectId("5cf9b8caaeeb19e36bd25af5")
  }

Donde el ObjectId es un identificador único que recibe ese documento, si nosotros no lo especificamos Mongo lo asignara automáticamente. Es obligatorio que exista ese campo en todos los documentos, el valor de este campo jamas se debe repetir en los documentos.

MongoDB tiene algo llamado atomicidad dentro de los documentos, quiere decir que cuando se realiza una operación de escritura esta debe ser atómica. Es decir que si no se llega a completar de manera correcta se realiza la operación de rollback, que es que el documento no se guarde dentro de la base de datos. Esto nos garantiza que la operación no se realice de forma parcial, como podría ser el escribir en el documento solo un campo aunque los demas tengan errores.

Insertar diferentes documentos en una colección

MongoDB nos da la opción de poder insertar diferentes documentos en la base de datos enviando un arreglo de objetos a través de la función insertMany(). La sintaxis se puede ver de la siguiente forma.

    db.collectionName.insertMany([
    {
      ...Document1
    },{
      ...Document2
    }])
<h3>Ejemplo</h3>

En el siguiente bloque de código se puede ver como agregamos un arreglo de objetos a la colección inventory

  
  db.inventory.insertMany( [
   { item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
   { item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
   { item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }] )

Si todos nuestros documentos se agregaron de la manera adecuada sin que sucediera un rollback, de respuesta podemos esperar por MongoDB un arreglo de objetos confirmándonos que se crearon correctamente devolviéndonos el _id de cada uno

{
  "acknowledged" : true,
  "insertedIds" : [
  	ObjectId("5cfd49c9edbc9424e14849a9"),
  	ObjectId("5cfd49c9edbc9424e14849aa"),
  	ObjectId("5cfd49c9edbc9424e14849ab"),
  	ObjectId("5cfd49c9edbc9424e14849ac"),
  	ObjectId("5cfd49c9edbc9424e14849ad"),
  	ObjectId("5cfd49c9edbc9424e14849ae"),
  	ObjectId("5cfd49c9edbc9424e14849af"),
  	ObjectId("5cfd49c9edbc9424e14849b0"),
  	ObjectId("5cfd49c9edbc9424e14849b1"),
  	ObjectId("5cfd49c9edbc9424e14849b2")
    ]
}

Búsqueda de documentos

En Mongo existen diferentes formas de buscar los documentos, podemos hacerlo a través de filtros o directamente por el objectId. Para esto se utilizan dos métodos, find() y findOne().

  • find() Nos regresa uno o mas documentos que cumplan con ciertas condiciones que especifiquemos, si no especificamos ninguna condición de búsqueda nos regresara todos los documentos de la colección.

    //buscamos el documento con _id que sea igual a 5cfd49c9edbc9424e14849ae//Como el id es único solo nos regresara un documento
      db.inventory.find("5cfd49c9edbc9424e14849ae")
      
      //Nos regresara todos los documentos donde el item sea igual a "canvas"
      db.inventory.find({item: "canvas"})
    
  • findOne() Nos regresa solo un documento que cumpla con ciertas condiciones, si no especificamos ninguna condición de búsqueda nos regresara el ultimo documento registrado en la colección.

    //buscamos el documento con _id que sea igual a 5cfd49c9edbc9424e14849ae//Como el id es único solo nos regresara un documento
      db.inventory.find("5cfd49c9edbc9424e14849ae")
      
      //Nos regresara el ultimo documento donde el item sea igual a "canvas"
      db.inventory.find({item: "canvas"})
    

Como se puede observar existen muchísimas formas de poder buscar un documento gracias a los filtros. Algo interesante de recordar es que los documentos que se almacenan en MongoDB no se almacenan en forma de JSON, si no de BSON. Por lo que algunas veces cuando realicemos búsquedas hay que tener en cuenta esto.

Por ejemplo si nosotros realizamos la búsqueda de un documento a través de su ObjectId con un filtro de la siguiente manera.

  db.inventory.findOne({_id: 'quieroBuscarEsteObjectId'})

Nos regresara null debido a que el objectId no es parte de la especificación de JSON (basicamente son incompatibles). Para esto usamos el método ObjectId() para realizar la búsqueda. La forma de usarlo la puedes ver en el siguiente ejemplo

  db.inventory.findOne({_id: ObjectId('quieroBuscarEsteObjectId')})

Query and Projection Operators

Algo importante de los querys en Mongo, es que en los filtros que hacemos podemos buscar mas de un parametro, y podemos implementar algo muy util en Mongo que son los Query and Projection Operators, que son operadores que nos ayudan a que se cumplan condiciones especificas dentro de los parametros de nuestro query. Estos son denotados con el simbolo de dolar $

Algunos ejemplos de estos operadores son

Operador
$eqEncuentra los valores que son iguales al valor de búsqueda
$gtEncuentra los valores que son mayores al valor de búsqueda
$gteEncuentra los valores que son mayores o iguales al valor de búsqueda
$inEncuentra cualquiera de los valores que coinciden con los elementos del array de búsqueda.
$ltEncuentra los valores que son menores al valor de búsqueda
$lteEncuentra los valores que son menores o iguales al valor de búsqueda.
$neEncuentra los valores que no son iguales al valor de búsqueda.
$ninEncuentra cualquiera de los valores que no coinciden con los elementos del array de búsqueda.
<h3>Ejemplo</h3>

Encuentra todos los documentos que tengan un estatus ‘A’ y que su cantidad sea menor a ‘30’ (lower than)

  db.inventory.find( { status: "A", qty: { $lt: 30 } } )

Actualizar documentos

Como en todo CRUD es necesario realizar la operacion de Actualizar (UPDATE), para eso Mongo se vale de los métodos updateOne() y updateMany() que análogamente funcionan de manera similar que findOne() y find().

La gran diferencia aquí consta en los parámetros que reciben estas funciones que actualizaran nuestros documentos. La estructura es la siguiente

  db.collectionName.updateOne(<filter>, <update>)

En el argumento de <filter> debe de ir la condición con la cual nosotros decidiremos que documentos actualizar, por ejemplo un filtro valido podría ser el objectId u otro podría ser todos los documentos que tuvieran una cantidad de piezas menor a 40.

En el argumento de update ira los campos que deseemos actualizar, pueden ser uno o varios los campos que podemos actualizar. Estos campos deben de ir después del operador $set

<h3>Ejemplo</h3>

Si queremos actualizar la cantidad de un solo producto que cumpla con el filtro, entonces podemos usar updateOne(). En este ejemplo actualizaremos el primer producto que tenga una cantidad mayor a 10 en el inventario y le colocaremos una status “B”

  db.inventory.updateOne({ qty: { $gt: 10 } },{ $set: { status: "B" } })
  //Solo actualiza el primero que encuentre en el orden natural //de registro en disco

En dado caso que quisiéramos que se actualizaran todos los productos con esa condición del filtro se utilizaría updateMany()

  db.inventory.updateOne({ qty: { $gt: 10 } },{ $set: { status: "B" } })
  //Actualizaria todos los que cumplan la condicion del filtro

Utilidades dentro del método update

Es importante saber que el método update(), updateOne() y updateMany() pueden recibir un tercer parámetro que sirven como opciones para saber que puede hacer el update bajo ciertos comportamientos. Todas estas opciones se pueden profundizar en la documentación de MongoDB.

Una de las opciones mas interesantes que tiene el update es la de upsert, si nosotros activamos este parámetro la actualización se puede comportar como un insert en caso de que el filtro no se cumpla.

<h3>Ejemplo</h3>

Imaginemos que hacemos una actualización por id en nuestra colección, pero resulta que el id no existe. Si no activamos la opcion de upsert lo valores que pasamos para actualizar no tendrán ningún efecto en la base de datos. Sin embargo si elupsert esta activo Mongo creara un nuevo documento con esos datos.

  db.inventory.update(
    { _id: "id_que_no_existe"},
    { $set: { qty: 40 } },
    { upsert: true }
)

Con la opción de upsert activa mongo nos creara un documento con el siguiente formato

{ "_id" : "algunID", "qty" : 40 }

Eliminacion de documentos

Al igual que los otros métodos dentro de Mongo, existe el deleteOne() y deleteMany(). Estos se comportan de manera muy similar a que findOne() y find(). Solo que al momento de cumplir con la condición del filtro estos métodos eliminaran al documento.

//Elimina solo el primer documento que encuentre con el criterio del filtro
db.collectionName.deleteOne(filter)
//Elimina todos los documentos que encuentre con el criterio del filtro
db.collectionName.deleteMany(filter)

Recomendaciones para implementar un CRUD

Como sabemos las operaciones de lectura no son riesgosas para los datos que tengamos almacenados en nuestra base de datos. Sin embargo las operaciones de escritura, actualización y eliminación de documentos pueden ser demasiado riesgosas si no se hacen bien.

Aqui hay algunas recomendaciones que se pueden seguir para no comprometer nuestros datos al hacer estas operaciones

  • Dejar que Mongo se haga cargo de la creación del id de nuestros documentos
  • Nunca hacer la operación delete sin antes poner un filtro. Esto lo único que causaría seria eliminar todos los documentos de la colección.
  • Para poder verificar que nuestro filtro cumple con la condición que nosotros queremos, podemos usar el método find() y verificar que documentos nos regresa.
  • Si llegamos a usar la opción upsert al momento de actualizar, es recomendable que lo que actualicemos sea un esquema general de nuestro documento. Aunque MongoDB no maneja esquemas, a veces es bueno implementarlos para tener una mejor organización de nuestros datos.
Escribe tu comentario
+ 2
Ordenar por:
2
15044Puntos

Tengo unas observaciones como por hacer feedback:

  1. la parte de Consultar ayuda sobre algún comando: el segundo comando le hace falta concatenar el .help
  2. el codigo para explicar el .findOne() es el mismo del .find()
  3. sería bueno que ya que en cada caso pusiste un ejemplo, añadieras uno en el de eliminación de documentos. se que no es necesario, es muy intuitivo de sacar, pero ya solo como por seguir el formato del articulo que creaste.
  4. una que otra tilde que se omitió en palabras como asignará, parámetro, útil, específicas (creo que en la parte de Query and Projection Operators se te olvidaron las tildes).
    De resto todo bien muchas gracias por el resumen
1
18369Puntos
10 meses

Muchas gracias por la retroalimentación 😄

2
3610Puntos

Muchas gracias @edevars, estaba perdido con esta clase, y con esta guía resolví varias dudas

1
18369Puntos
8 meses

No hay de que, un gusto el poderte haber ayudado 😊

1

Es muy práctico tu instructivo, resuelve a mayor detalle varias dudas que se quedan al aire en el video.