sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB $mergeObjects

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" : { } }