MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB - $project document imbriqué au niveau racine

Pour MongoDB 3.6 et versions ultérieures, utilisez le cadre d'agrégation avec un $replaceRoot pipeline qui peut être appliqué conjointement avec le $mergeObjects opérateur comme newRoot expression.

Cette expression

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

fusionnera les champs de niveau supérieur du document avec ceux des champs incorporés du sous-doc. Ainsi, à la fin, votre opération d'agrégation sera la suivante :

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

Sinon, vous auriez besoin d'un mécanisme pour obtenir toutes les clés dynamiques dont vous avez besoin pour assembler le $project dynamique document. Ceci est possible grâce à Map-Reduce . L'opération mapreduce suivante remplira une collection distincte avec toutes les clés en tant que _id valeurs :

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"
})

Pour obtenir une liste de toutes les clés dynamiques, exécutez distinct sur la collection résultante :

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

Maintenant, étant donné la liste ci-dessus, vous pouvez assembler votre $project document de pipeline d'agrégation en créant un objet dont les propriétés seront définies dans une boucle. Normalement, votre $project document aura cette structure :

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

Ainsi, en utilisant la liste ci-dessus des clés de sous-document, vous pouvez construire dynamiquement ce qui précède en utilisant JavaScript reduce() méthode :

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]);