MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB - $project verschachteltes Dokument auf Stammebene

Verwenden Sie für MongoDB 3.6 und höher das Aggregationsframework mit einem $replaceRoot Pipeline, die in Verbindung mit $mergeObjects Operator als newRoot Ausdruck.

Dieser Ausdruck

{ "$mergeObjects": ["$subdoc", "$$ROOT"] }

wird die Felder der obersten Ebene im Dokument mit denen in den eingebetteten Feldern des Unterdokuments zusammenführen, sodass Ihre aggregierte Operation am Ende wie folgt aussieht:

db.collection.aggregate([
    { "$replaceRoot": { 
        "newRoot": { 
            "$mergeObjects": [ "$subdoc", "$$ROOT" ] 
        } 
    } },
    { "$project": { "subdoc": 0 } }  
])

Andernfalls benötigen Sie einen Mechanismus, um alle dynamischen Schlüssel zu erhalten, die Sie zum Zusammenstellen des dynamischen $project benötigen dokumentieren. Dies ist möglich durch Map-Reduce . Die folgende mapreduce-Operation füllt eine separate Sammlung mit allen Schlüsseln als _id Werte:

mr = db.runCommand({
    "mapreduce": "my_collection",
    "map" : function() {
        for (var key in this.subdoc) { emit(key, null); }
    },
    "reduce" : function(key, stuff) { return null; }, 
    "out": "my_collection" + "_keys"
})

Um eine Liste aller dynamischen Schlüssel zu erhalten, führen Sie den Befehl „distinct“ für die resultierende Sammlung aus:

db[mr.result].distinct("_id")
["field2", "field3", ...]

Anhand der obigen Liste können Sie nun Ihr $project zusammenstellen Aggregations-Pipeline-Dokument, indem Sie ein Objekt erstellen, dessen Eigenschaften in einer Schleife festgelegt werden. Normalerweise Ihr $project Dokument wird diese Struktur haben:

var project = {
    "$project": {
        "field1": 1,
        "field2": "$subdoc.field2",
        "field3": "$subdoc.field3"
    }
};

Wenn Sie also die obige Liste von Unterdokumentschlüsseln verwenden, können Sie das obige mithilfe von JavaScripts reduce() Methode:

var subdocKeys = db[mr.result].distinct("_id"),
    obj = subdocKeys.reduce(function (o, v){
      o[v] = "$subdoc." + v;
      return o;
    }, { "field1": 1 }),
    project = { "$project": obj };

db.collection.aggregate([project]);