Schließen Sie alle vorhandenen Felder ein und fügen Sie dem Dokument neue Felder hinzu

123

Ich möchte eine $ -Projektaggregationsphase definieren, in der ich sie anweisen kann, ein neues Feld hinzuzufügen und alle vorhandenen Felder einzuschließen, ohne alle vorhandenen Felder auflisten zu müssen.

Mein Dokument sieht so aus, mit vielen Feldern:

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

Ich möchte eine Aggregationsoperation wie folgt durchführen:

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

Gibt es so etwas wie ein Schlüsselwort "Alle Felder einschließen", das ich in diesem Fall verwenden kann, oder eine andere Möglichkeit, um zu vermeiden, dass jedes Feld separat aufgelistet werden muss?

samuelluis
quelle
1
Diese Funktion wird in der nächsten Hauptversion 2.6 verfügbar sein. Sie können es im instabilen Entwicklungszweig versuchen - verwenden Sie "$$ ROOT", um auf das gesamte eingehende Dokument zu verweisen. Siehe Details in diesem Ticket: jira.mongodb.org/browse/SERVER-5916
Asya Kamsky
1
Dieses Problem wird auch unter stackoverflow.com/questions/20497499/… mit einigen anderen nützlichen und unterschiedlichen Antworten angesprochen .
Vince Bowdren

Antworten:

168

In 4.2+ können Sie den $setAggregationspipeline-Operator verwenden, der nichts anderes als ein $addFieldsin 3.4 hinzugefügter Alias ​​ist

Die $addFieldsStufe entspricht einer $projectStufe, in der alle vorhandenen Felder in den Eingabedokumenten explizit angegeben und die neuen Felder hinzugefügt werden.

db.collection.aggregate([
    { "$addFields": { "custom_field": "$obj.obj_field1" } }
])
Styvane
quelle
2
Irgendeine Idee, wie man es im C # -Treiber verwendet? scheint es nicht zu existieren
Homam
Ich bin nicht mit dem C # -Treiber vertraut, aber $addFieldsneu in MongoDB 3.4, das von der C # -Treiberversion 2.5+ unterstützt wird
Styvane
Ich habe nach einer Möglichkeit gesucht, dies im C # -Treiber zu tun, und bis jetzt sieht es so aus, als würde die Verwendung so etwas wieIAggregateFluent<TResult>.AppendStage(new JsonPipelineStageDefinition<TInput, TOutput>("{ $addFields : { myField: 'myValue' }}")
sboisse
4
Ich entdeckte, dass es sogar ein Feld ersetzen kann, wenn Sie den gleichen Feldnamen angeben
CME64
79

Sie können $$ ROOT verwenden, um auf das Stammdokument zu verweisen. Behalten Sie alle Felder dieses Dokuments in einem Feld und versuchen Sie es danach abzurufen (abhängig von Ihrem Client-System: Java, C ++, ...)

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

        }
    },
    ... //group, match, and whatever...
]
Deka
quelle
17
Aber dies wird ein eingebettetes Dokument erstellen, das als documentOption zum Erstellen eines zusammengeführten Dokuments bezeichnet wird.
Wäre
2
Kennt jemand die Lösung, um alle Schlüsselwertpaare zu durchlaufen, ohne das eingebettete Dokument zu erstellen?
Ugotchi
11
Halten Sie die Luft an. MongoDB 3.4 wird mit einer Aggregationsstufe von $ addFields geliefert , die genau dies tut. Siehe stackoverflow.com/a/24557029/4653485 .
Jérôme
Dies scheint die derzeit beste Lösung zu sein, da Sie (zumindest in JS) dann den Spread-Operator verwenden können, um Ihr ursprüngliches Objekt mit dem neuen custom_fieldangehängten neu zu erstellen. const newObj = { ...result.document, custom_field: result.custom_field }
ffritz
7

>>> Gibt es so etwas wie das Schlüsselwort "Alle Felder einschließen", das ich in diesem Fall oder in einer anderen Lösung verwenden kann?

Leider gibt es keinen Operator, der "alle Felder" in die Aggregationsoperation einbezieht. Der einzige Grund, warum, weil die Aggregation hauptsächlich erstellt wird, um Daten aus Sammlungsfeldern (Summe, Durchschnitt usw.) zu gruppieren / zu berechnen und alle Felder der Sammlung zurückzugeben, ist kein direkter Zweck.

Victoria Malaya
quelle
... weil die Aggregation hauptsächlich zum Gruppieren / Berechnen von Daten aus Sammlungsfeldern erstellt wird ... Die beste Antwort in der Tat!
Felipsmartins
1
Sie haben eine Sammlung postsmit _id, title, body, liken Feldern. Das Likes-Feld ist ein Array von Benutzer-ID, denen der Beitrag gefällt. Wie können Sie alle Beiträge mit allen _id, title, body, likeCount auflisten? Die Rückgabe aller Felder ist in diesem Fall ein direkter Zweck.
doc_id
3

Ab Version 2.6.4 verfügt Mongo DB nicht über eine solche Funktion für die $projectAggregationspipeline. Aus den Dokumenten für $project:

Leitet die Dokumente mit nur den angegebenen Feldern an die nächste Stufe in der Pipeline weiter. Die angegebenen Felder können vorhandene Felder aus den Eingabedokumenten oder neu berechnete Felder sein.

und

Das Feld _id ist standardmäßig in den Ausgabedokumenten enthalten. Um die anderen Felder aus den Eingabedokumenten in die Ausgabedokumente aufzunehmen, müssen Sie die Aufnahme in $ project explizit angeben.

Ghopper21
quelle
2

Sie können Ihrem Dokument neue Felder hinzufügen $addFields

aus docs

und für alle Felder in Ihrem Dokument können Sie verwenden $$ROOT

db.collection.aggregate([

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

Laut der Antwort von @Deka können Sie für den c # mongodb-Treiber 2.5 das gruppierte Dokument mit allen Schlüsseln wie unten erhalten.

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