Campos anidados del proyecto MongoDB

Mehvish Ashiq 30 enero 2023
  1. Campos anidados del proyecto MongoDB
  2. Utilice la etapa de agregación $project para proyectar campos anidados en MongoDB
  3. Use la etapa de agregación $unset para obtener campos anidados que excluyan los especificados en MongoDB
  4. Utilice un bucle forEach() para obtener campos anidados en MongoDB
  5. Utilice el método mapReduce() para proyectar campos anidados en MongoDB
Campos anidados del proyecto MongoDB

Hoy aprenderemos a usar las etapas de agregación $project y $unset, el ciclo forEach() y el método mapReduce() para proyectar campos anidados mientras consultamos datos en MongoDB.

Campos anidados del proyecto MongoDB

En MongoDB, podemos recuperar todos los documentos utilizando el método find(), pero ¿qué pasa si solo queremos acceder a campos anidados específicos? Aquí es donde usamos la proyección.

Podemos proyectar campos anidados de varias maneras. Aquí aprenderemos sobre las siguientes soluciones para proyectar campos anidados.

  1. Usa la etapa de agregación $project
  2. Utilice la etapa de agregación $unset
  3. Usa el ciclo forEach()
  4. Usa la función mapReduce()

Para aprender los enfoques anteriores, creemos una colección llamada anidada que contenga un documento. También puede usar la consulta que se proporciona a continuación para hacer un seguimiento con nosotros.

Código de ejemplo:

// MongoDB version 5.0.8

> db.nested.insertOne(
    {
        "name": {
            "first_name": "Mehvish",
            "last_name": "Ashiq",
         },
         "contact": {
            "phone":{"type": "manager", "number": "123456"},
            "email":{ "type": "office", "mail": "delfstack@example.com"}
         },
         "country_name" : "Australien",
         "posting_locations" : [
             {
                 "city_id" : 19398,
                 "city_name" : "Bondi Beach (Sydney)"
             },
             {
                  "city_id" : 31101,
                  "city_name" : "Rushcutters Bay (Sydney)"
             },
             {
                  "city_id" : 31022,
                  "city_name" : "Wolly Creek (Sydney)"
             }
          ],
          "regions" : {
              "region_id" : 796,
              "region_name" : "Australien: New South Wales (Sydney)"
          }
    }
);

Utilice db.nested.find().pretty(); en mongo shell para ver los datos insertados.

Utilice la etapa de agregación $project para proyectar campos anidados en MongoDB

Código de ejemplo:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> var project = {};
> project["id"] = "$"+current_location+".city_id";
> project["name"] = "$"+current_location+".city_name";
> project["regions"] = 1;

> var find = {};
> find[current_location] = {"$exists":true};

> db.nested.aggregate([
    { $match : find },
    { $project : project }
]).pretty()

Producción :

{
        "_id" : ObjectId("62a96d397c7e3688aea26d0d"),
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "id" : [
                19398,
                31101,
                31022
        ],
        "name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

Aquí, guardamos el campo de primer nivel llamado ubicaciones_de_publicación en una variable llamada ubicación_actual.

Luego, usamos esa variable para acceder a city_id y city_name y los guardamos en el objeto project mientras usamos la notación de paréntesis para crear propiedades para el objeto project. Además, guardamos el campo regions en el objeto project["regions"].

A continuación, tenemos otro objeto llamado find que usaremos en el método aggregate() para hacer coincidir los documentos. En el método aggregate(), utilizamos la etapa $match para hacer coincidir los documentos y $project para proyectar los campos, ya sean anidados o de primer nivel.

Usamos $project para especificar qué campos queremos mostrar en la salida. Podemos usar la siguiente solución si estamos interesados ​​en proyectar los campos anidados especificados solo sin ninguna consulta de filtro.

Código de ejemplo:

// MongoDB version 5.0.8

> var current_location = "posting_locations";
> db.nested.aggregate({
    $project: {
         "_id": 0,
         "city_id": "$" + current_location + ".city_id",
         "city_name": "$" + current_location + ".city_name",
         "regions": 1
    }
}).pretty();

Producción :

{
        "regions" : {
                "region_id" : 796,
                "region_name" : "Australien: New South Wales (Sydney)"
        },
        "city_id" : [
                19398,
                31101,
                31022
        ],
        "city_name" : [
                "Bondi Beach (Sydney)",
                "Rushcutters Bay (Sydney)",
                "Wolly Creek (Sydney)"
        ]
}

Use la etapa de agregación $unset para obtener campos anidados que excluyan los especificados en MongoDB

Código de ejemplo:

// MongoDB version 5.0.8

> db.nested.aggregate({
        $unset: ["posting_locations.city_id", "contact", "regions", "name", "_id"]
}).pretty()

Producción :

{
        "country_name" : "Australien",
        "posting_locations" : [
                {
                        "city_name" : "Bondi Beach (Sydney)"
                },
                {
                        "city_name": "Rushcutters Bay (Sydney)"
                },
                {
                        "city_name": "Wolly Creek (Sydney)"
                }
        ]
}

Aquí, usamos el operador $unset, que se usa para eliminar el campo especificado o la matriz de campos.

Recuerde que usamos la notación de puntos para especificar los documentos incrustados o la matriz de documentos. El operador $unset no realiza ninguna operación si el campo dado no existe.

Cuando usamos $ para hacer coincidir los elementos de una matriz, el operador $unset reemplaza los elementos coincidentes con null en lugar de eliminarlos de la matriz. Este comportamiento ayuda a mantener consistentes las posiciones de los elementos y el tamaño de la matriz.

Utilice un bucle forEach() para obtener campos anidados en MongoDB

Código de ejemplo:

// MongoDB version 5.0.8

> var bulk = db.newcollection.initializeUnorderedBulkOp(),
   counter = 0;

> db.nested.find().forEach(function(doc) {
    var document = {};
    document["name"] = doc.name.first_name + " " + doc.name.last_name;
    document["phone"] = doc.contact.phone.number;
    document["mail"] = doc.contact.email.mail;
    bulk.insert(document);
    counter++;
    if (counter % 1000 == 0) {
        bulk.execute();
        bulk = db.newcollection.initializeUnorderedBulkOp();
    }
});

> if (counter % 1000 != 0) { bulk.execute(); }

Verás algo similar a lo siguiente.

BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 1,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})

A continuación, ejecute el siguiente comando en su mongo shell para ver los campos proyectados.

// MongoDB version 5.0.8

> db.newcollection.find().pretty();

Producción :

{
        "_id" : ObjectId("62a96f2d7c7e3688aea26d0e"),
        "name" : "Mehvish Ashiq",
        "phone" : "123456",
        "mail" : "delfstack@example.com"
}

Para aprender este código de ejemplo, supongamos que queremos tomar ciertos campos anidados e insertarlos en una nueva colección. Aquí, insertar los campos transformados como un documento en una nueva colección puede afectar nuestras operaciones en función del tamaño de la colección anidada.

Podemos evitar este rendimiento de inserción lento mediante el uso de una nueva API desordenada inserción masiva. Agilizará las operaciones de inserción mediante el envío masivo y nos dará retroalimentación en tiempo real sobre si la operación tuvo éxito o falló.

Por lo tanto, estamos utilizando la API de inserción masiva para insertar la estructura de datos deseada en la colección nueva colección, donde los nuevos documentos se crearán con el bucle forEach() del cursor de la colección anidada. Para crear nuevas propiedades, usamos la notación de paréntesis.

Para este código, asumimos que tenemos una gran cantidad de datos. Entonces, enviaremos las operaciones a un servidor en lotes de 1000 para realizar la operación de inserción masiva.

Como resultado, nos brinda un buen rendimiento porque no enviamos cada solicitud sino solo una vez por cada 1000 solicitudes al servidor.

Utilice el método mapReduce() para proyectar campos anidados en MongoDB

Código de ejemplo:

// MongoDB version 5.0.8

> function map() {
    for(var i in this.posting_locations) {
         emit({
             "country_id" : this.country_id,
             "city_id" : this.posting_locations[i].city_id,
             "region_id" : this.regions.region_id
         },1);
    }
}

> function reduce(id,docs) {
      return Array.sum(docs);
}

> db.nested.mapReduce(map,reduce,{ out : "map_reduce_output" } )

Ahora, ejecute la siguiente consulta para ver el resultado.

// MongoDB version 5.0.8
> db.map_reduce_output.find().pretty();

Producción :

{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 19398,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31022,
                "region_id" : 796
        },
        "value" : 1
}
{
        "_id" : {
                "country_id" : undefined,
                "city_id" : 31101,
                "region_id" : 796
        },
        "value" : 1
}

Para este código de ejemplo, usamos la función mapReduce() para realizar map-reduce en todos los documentos de la colección anidada. Para eso, tenemos que seguir un proceso de tres pasos que se explica brevemente a continuación.

  • Defina la función map() para procesar cada documento de entrada. En esta función, la palabra clave this se refiere al documento actual que está siendo procesado por la operación map-reduce, y la función emit() asigna los valores dados a las claves y los devuelve.
  • Aquí, definimos la función reduce() correspondiente, que es el lugar real donde se lleva a cabo la agregación de datos. Toma dos argumentos (claves y valores); nuestro ejemplo de código toma id y docs.

    Recuerda que los elementos de los docs son devueltos por la función emit() del método map(). En este paso, la función reduce() reduce la matriz docs a la suma de sus valores (elementos).

  • Finalmente, realizamos map-reduce en todos los documentos de la colección anidada usando las funciones map() y reduce(). Usamos out para guardar la salida en la colección especificada, que es map_reduce_output en este caso.
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

Artículo relacionado - MongoDB Projection