web-dev-qa-db-fra.com

Inclure tous les champs existants et ajouter de nouveaux champs au document

J'aimerais définir une étape d'agrégation de $ projet dans laquelle je peux lui demander d'ajouter un nouveau champ et d'inclure tous les champs existants, sans avoir à répertorier tous les champs existants.

Mon document ressemble à ceci, avec de nombreux champs:

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

Je veux faire une opération d'agrégation comme ceci:

[
    {
        $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...
]

Y a-t-il quelque chose comme un mot clé "inclure tous les champs" que je puisse utiliser dans ce cas, ou un autre moyen d'éviter de lister chaque champ séparément?

102
samuelluis

Dans 4.2+, vous pouvez utiliser le $set opérateur de pipeline d'agrégation auquel rien d'autre qu'un alias à $addFields ajouté dans 3.4

Le $addFields _ stage équivaut à $project étape qui spécifie explicitement tous les champs existants dans les documents d’entrée et ajoute les nouveaux champs.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
139
styvane

Vous pouvez utiliser $$ ROOT pour référencer le document racine. Conservez tous les champs de ce document dans un champ et essayez ensuite de l'obtenir (selon votre système client: Java, C++, ...)

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

        }
    },
    ... //group, match, and whatever...
]
68
Deka

>>> Il y a quelque chose comme le mot clé "inclure tous les champs" que je peux utiliser dans ce cas ou une autre solution?

Malheureusement, il n'y a pas d'opérateur pour "inclure tous les champs" dans l'opération d'agrégation. La seule raison pour laquelle, étant donné que l'agrégation est généralement créée pour regrouper/calculer des données à partir de champs de collection (somme, moy, etc.) et renvoyer tous les champs de la collection n'est pas un objectif direct.

7
Victoria Malaya

A partir de la version 2.6.4, Mongo DB n’a pas cette fonctionnalité pour le $project pipeline d'agrégation. À partir de docs pour $project:

Transmet les documents contenant uniquement les champs spécifiés à la prochaine étape du pipeline. Les champs spécifiés peuvent être des champs existants des documents d'entrée ou des champs nouvellement calculés.

et

Le champ _id est, par défaut, inclus dans les documents de sortie. Pour inclure les autres champs des documents d'entrée dans les documents de sortie, vous devez spécifier explicitement l'inclusion dans $ project.

3
Ghopper21

Pour ajouter de nouveaux champs à votre document, vous pouvez utiliser $ addFields

[de docs] [1]

et à tous les champs de votre document, vous pouvez utiliser $$ ROOT

db.collection.aggregate([

    { "$addFields": { "custom_field": "$obj.obj_field1" } },
    { "$group": {
            _id : "$field1",
            data: { $Push : "$$ROOT" }
        }}
])


  [1]: https://docs.mongodb.com/master/reference/operator/aggregation/addFields/
0
Deeksha Sharma

selon @Deka, pour le pilote c # mongodb 2.5, vous pouvez obtenir le document groupé avec toutes les clés comme ci-dessous;

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);
0
mr.byte