En MongoDB, el $mergeObjects
El operador de canalización de agregación combina varios documentos en un solo documento.
Sintaxis
Los $mergeObjects
operador admite dos sintaxis.
Sintaxis 1:
{ $mergeObjects: [ <document1>, <document2>, ... ] }
Sintaxis 2:
{ $mergeObjects: <document> }
La primera sintaxis acepta múltiples argumentos y la segunda sintaxis acepta un argumento.
Ejemplo de sintaxis 1 (múltiples argumentos)
La primera sintaxis consiste en proporcionar $mergeObjects
con más de un argumento/documento. $mergeObjects
luego combina esos documentos en uno.
Supongamos que tenemos una colección llamada users
con el siguiente documento:
{ "_id" : 1, "name" : { "f_name" : "Homer", "l_name" : "Simpson" }, "contact" : { "email" : "[email protected]", "ph" : null } }
Podemos usar $mergeObjects
para fusionar el name
y contact
campos:
db.users.aggregate(
[
{
$project:
{
user: { $mergeObjects: [ "$name", "$contact" ] }
}
}
]
).pretty()
Resultado:
{ "_id" : 1, "user" : { "f_name" : "Homer", "l_name" : "Simpson", "email" : "[email protected]", "ph" : null } }
En este caso, fusionamos ambos campos en un solo campo llamado user
. Si tuviéramos más campos/documentos, también podríamos haberlos fusionado si hubiéramos querido.
Nombres de campos duplicados
Si los documentos que se fusionarán contienen nombres de campo duplicados, $mergeObjects
sobrescribe el campo a medida que combina los documentos. Por lo tanto, el campo del documento resultante contiene el valor del último documento fusionado para ese campo.
Supongamos que tenemos el siguiente documento:
{ "_id" : 2, "name" : { "f_name" : "Peter", "l_name" : "Griffin" }, "contact" : { "email" : "[email protected]", "f_name" : "Bart" } }
Podemos ver que ambos documentos contienen un campo llamado f_name
.
Esto es lo que sucede cuando fusionamos esos documentos:
db.users.aggregate(
[
{ $match: { _id: 2 } },
{
$project:
{
user: { $mergeObjects: [ "$name", "$contact" ] }
}
}
]
).pretty()
Resultado:
{ "_id" : 2, "user" : { "f_name" : "Bart", "l_name" : "Griffin", "email" : "[email protected]" } }
El f_name
el campo en el documento resultante contiene Bart
, que es el valor del último documento que se fusionó.
Valores nulos
Si fusiona un documento con null
, el documento resultante se devolverá sin cambios.
Pero si todos los documentos a fusionar son null
, luego se devuelve un documento vacío.
Supongamos que tenemos los siguientes documentos:
{ "_id" : 3, "name" : { "f_name" : "Hubert", "l_name" : "Farnsworth" }, "contact" : null } { "_id" : 4, "name" : null, "contact" : null }
Esto es lo que sucede cuando fusionamos el name
y contact
campos en esos dos documentos:
db.users.aggregate(
[
{ $match: { _id: { $in: [ 3, 4 ] } } },
{
$project:
{
user: { $mergeObjects: [ "$name", "$contact" ] }
}
}
]
)
Resultado:
{ "_id" : 3, "user" : { "f_name" : "Hubert", "l_name" : "Farnsworth" } } { "_id" : 4, "user" : { } }
Ejemplos de sintaxis 2 (argumento único)
Aquí hay dos ejemplos que usan la sintaxis de argumento único.
$group
Acumulador de etapa
En el primer ejemplo, $mergeObjects
se usa como un $group
acumulador de etapa.
Supongamos que tenemos una colección llamada products
con los siguientes documentos:
{ "_id" : 1, "product" : "Shirt", "inventory" : { "blue" : 10, "red" : 2 } } { "_id" : 2, "product" : "Shirt", "inventory" : { "green" : 3, "black" : 1 } } { "_id" : 3, "product" : "Shorts", "inventory" : { "blue" : 2, "red" : 8 } } { "_id" : 4, "product" : "Shorts", "inventory" : { "green" : 5, "black" : 3 } }
Podemos agrupar estos documentos por su product
y luego use $mergeObjects
para fusionar el inventory
campo para cada grupo:
db.products.aggregate( [
{ $group: {
_id: "$product",
mergedProducts: { $mergeObjects: "$inventory" }
}
}
]).pretty()
Resultado:
{ "_id" : "Shorts", "mergedProducts" : { "blue" : 2, "red" : 8, "green" : 5, "black" : 3 } } { "_id" : "Shirt", "mergedProducts" : { "blue" : 10, "red" : 2, "green" : 3, "black" : 1 } }
Arreglos
Este ejemplo aplica $mergeObjects
a un solo documento que contiene un campo con una matriz de documentos.
Supongamos que tenemos una colección llamada test
con los siguientes documentos:
{ "_id" : 1, "data" : [ { "a" : 1, "b" : 2 }, { "c" : 3, "d" : 4 } ] }
Podemos aplicar $mergeObjects
a los data
campo:
db.test.aggregate(
[
{
$project:
{
result: { $mergeObjects: "$data" }
}
}
]
)
Resultado:
{ "_id" : 1, "result" : { "a" : 1, "b" : 2, "c" : 3, "d" : 4 } }
Campos faltantes
$mergeObjects
ignora cualquier campo faltante. Es decir, si proporciona un campo que no existe, lo ignora. Si ninguno de los campos existe, devuelve un documento vacío.
Ejemplo:
db.users.aggregate(
[
{
$project:
{
user: { $mergeObjects: [ "$name", "$oops" ] }
}
}
]
).pretty()
Resultado:
{ "_id" : 1, "user" : { "f_name" : "Homer", "l_name" : "Simpson" } } { "_id" : 2, "user" : { "f_name" : "Peter", "l_name" : "Griffin" } } { "_id" : 3, "user" : { "f_name" : "Hubert", "l_name" : "Farnsworth" } } { "_id" : 4, "user" : { } }
Sin embargo, esto es lo que sucede cuando ninguno de los campos existen:
db.users.aggregate(
[
{
$project:
{
user: { $mergeObjects: [ "$wrong", "$oops" ] }
}
}
]
).pretty()
Resultado:
{ "_id" : 1, "user" : { } } { "_id" : 2, "user" : { } } { "_id" : 3, "user" : { } } { "_id" : 4, "user" : { } }
El resultado es un documento vacío.
Es lo mismo cuando se usa la sintaxis de un solo argumento.
Ejemplo:
db.products.aggregate( [
{ $group: {
_id: "$product",
mergedProducts: { $mergeObjects: "$oops!" }
}
}
]).pretty()
Resultado:
{ "_id" : "Shorts", "mergedProducts" : { } } { "_id" : "Shirt", "mergedProducts" : { } }