Incluya todos los campos existentes y agregue nuevos campos al documento

123

Me gustaría definir una etapa de agregación de $ project donde pueda indicarle que agregue un nuevo campo e incluya todos los campos existentes, sin tener que enumerar todos los campos existentes.

Mi documento se ve así, con muchos campos:

{
    obj: {
        obj_field1: "hi",
        obj_field2: "hi2"
    },
    field1: "a",
    field2: "b",
    ...
    field26: "z"
}

Quiero hacer una operación de agregación como esta:

[
    {
        $project: {
            custom_field: "$obj.obj_field1",
            //the next part is that I don't want to do
            field1: 1,
            field2: 1,
            ...
            field26: 1
        }
    },
    ... //group, match, and whatever...
]

¿Hay algo como una palabra clave "incluir todos los campos" que pueda usar en este caso, o alguna otra forma de evitar tener que enumerar cada campo por separado?

samuelluis
fuente
1
Esta característica llegará en la próxima versión principal 2.6. Puede probarlo en la rama de desarrollo inestable: use "$$ ROOT" para consultar todo el documento entrante. Ver detalles en este boleto: jira.mongodb.org/browse/SERVER-5916
Asya Kamsky
1
Este problema también se plantea en stackoverflow.com/questions/20497499/… , con algunas otras respuestas útiles y diferentes.
Vince Bowdren

Respuestas:

168

En 4.2+, puede usar el $setoperador de canalización de agregación que no es más que un alias para $addFieldsagregar en 3.4

La $addFieldsetapa es equivalente a una $projectetapa que especifica explícitamente todos los campos existentes en los documentos de entrada y agrega los nuevos campos.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
Styvane
fuente
2
¿Alguna idea de cómo usarlo en el controlador C #? parece que no existe
Homam
No estoy familiarizado con el controlador C # pero $addFieldses nuevo en MongoDB 3.4, que es compatible con la versión 2.5+ del controlador C #
styvane
He estado buscando una manera de hacer esto en el controlador C #, y hasta ahora parece que la forma de hacerlo sería usar algo comoIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse
44
Descubrí que incluso puede reemplazar un campo si especifica el mismo nombre de campo
CME64
79

Puede usar $$ ROOT para hacer referencia al documento raíz. Mantenga todos los campos de este documento en un campo e intente obtenerlo después de eso (dependiendo de su sistema cliente: Java, C ++, ...)

 [
    {
        $project: {
            custom_field: "$obj.obj_field1",
            document: "$$ROOT"

        }
    },
    ... //group, match, and whatever...
]
Deka
fuente
17
Pero esto creará un documento incrustado llamado documentuna opción para crear un documento combinado hubiera sido mejor ...
Alexander Suraphel
2
¿Alguien sabe de la solución para pasar por todos los pares de valores clave sin crear el documento incrustado?
ugotchi
11
Contenga la respiración. MongoDB 3.4 vendrá con la etapa de agregación $ addFields que hace exactamente esto. Ver stackoverflow.com/a/24557029/4653485 .
Jérôme
Esta parece ser la mejor solución actual, ya que puede (al menos en JS) usar el operador de propagación para reconstruir su objeto original con el nuevo custom_fieldadjunto. const newObj = { ...result.document, custom_field: result.custom_field }
ffritz
7

>>> ¿Hay algo como la palabra clave "incluir todos los campos" que puedo usar en este caso o alguna otra solución?

Desafortunadamente, no hay operador para "incluir todos los campos" en la operación de agregación. La única razón es porque la agregación se crea principalmente para agrupar / calcular datos de los campos de la colección (suma, promedio, etc.) y devolver todos los campos de la colección no es un propósito directo.

Victoria Malaya
fuente
... porque la agregación se crea principalmente para agrupar / calcular datos de los campos de recopilación ... ¡La mejor respuesta de hecho!
felipsmartins 01 de
1
tienes una colección postscon _id, título, cuerpo, me gusta campos. El campo Me gusta es una matriz de _id de usuario a quien le gusta la publicación. ¿Cómo podrías enumerar todas las publicaciones con todos los _id, title, body, likeCount? Devolver todos los campos es un propósito directo en este caso.
doc_id
3

A partir de la versión 2.6.4, Mongo DB no tiene esa función para la $projectcanalización de agregación. De los documentos para $project:

Pasa los documentos con solo los campos especificados a la siguiente etapa de la canalización. Los campos especificados pueden ser campos existentes de los documentos de entrada o campos recién calculados.

y

El campo _id se incluye, por defecto, en los documentos de salida. Para incluir los otros campos de los documentos de entrada en los documentos de salida, debe especificar explícitamente la inclusión en $ project.

Ghopper21
fuente
2

Para agregar nuevos campos a su documento, puede usar $addFields

de los documentos

y a todos los campos en su documento, puede usar $$ROOT

db.collection.aggregate([

{ "$addFields": { "custom_field": "$obj.obj_field1" } },
{ "$group": {
        _id : "$field1",
        data: { $push : "$$ROOT" }
    }}
])
Deeksha Sharma
fuente
0

de acuerdo con la respuesta de @Deka, para c # mongodb driver 2.5 puede obtener el documento agrupado con todas las teclas como a continuación;

var group = new BsonDocument
{
 { "_id", "$groupField" },
 { "_document", new BsonDocument { { "$first", "$$ROOT" } } }
};

ProjectionDefinition<BsonDocument> projection = new BsonDocument{{ "document", "$_document"}};
var result = await col.Aggregate().Group(group).Project(projection).ToListAsync();

// For demo first record 
var fistItemAsT = BsonSerializer.Deserialize<T>(result.ToArray()[0]["document"].AsBsonDocument);
Sr. Byte
fuente