sql >> Database >  >> NoSQL >> MongoDB

MongoDB Totale som van elke sleutel op een subdocument

Zoals gezegd is het verwerken van dergelijke documenten niet mogelijk met het aggregatieraamwerk, tenzij u daadwerkelijk alle sleutels gaat aanleveren, zoals:

db.events.aggregate([
   { "$group": {
       "_id": "$app_id",
       "event_count": { "$sum": "$event_count" },
       "0": { "$sum": "$event_count_per_type.0" },
       "10": { "$sum": "$event_count_per_type.10" }
       "20": { "$sum": "$event_count_per_type.20" }
       "30": { "$sum": "$event_count_per_type.30" }
   }}
])

Maar je moet natuurlijk wel expliciet elke . specificeren sleutel waaraan u wilt werken. Dit geldt voor zowel het aggregatieraamwerk als de algemene querybewerkingen in MongoDB. Om toegang te krijgen tot elementen die in dit "subdocument"-formulier zijn genoteerd, moet u het "exacte pad" naar het element specificeren om er iets mee te kunnen doen.

Het aggregatieraamwerk en algemene zoekopdrachten hebben geen concept van "traversal", wat betekent dat ze niet "elke sleutel" van een document kunnen verwerken. Daarvoor is een taalconstructie nodig die niet in deze interfaces wordt geboden.

Over het algemeen is het gebruik van een "sleutelnaam" als een gegevenspunt waarbij de naam in feite een "waarde" vertegenwoordigt een beetje een "anti-patroon". Een betere manier om dit te modelleren zou zijn om een ​​array te gebruiken en je "type" als een waarde op zichzelf weer te geven:

{
    "app_id": "DHJFK67JDSJjdasj909",
    "date: ISODate("2014-08-07T00:00:00.000Z"),
    "event_count": 32423,
    "events": [
        { "type": 0,  "value": 322  },
        { "type": 10, "value": 4234 },
        { "type": 20, "value": 653  },
        { "type": 30, "value": 7562 }
    ]
}

Merk ook op dat de "datum" nu een echt datumobject is in plaats van een string, wat ook een goede gewoonte is om te doen. Dit soort gegevens is echter gemakkelijk te verwerken met het aggregatieraamwerk:

db.events.aggregate([
    { "$unwind": "$events" },
    { "$group": {
        "_id": { 
            "app_id": "$app_id",
            "type": "$events.type"
        },
        "event_count": { "$sum": "$event_count" },
        "value": { "$sum": "$value" }
    }},
    { "$group": {
        "_id": "$_id.app_id",
        "event_count": { "$sum": "$event_count" },
        "events": { "$push": { "type": "$_id.type", "value": "$value" } }
    }}
]) 

Dat toont een groepering in twee fasen die eerst de totalen per "type" krijgt zonder elke "sleutel" op te geven, omdat dat niet langer nodig is, en vervolgens terugkeert als een enkel document per "app_id" met de resultaten in een array zoals ze oorspronkelijk waren opgeslagen. Dit gegevensformulier is over het algemeen veel flexibeler om naar bepaalde "types" of zelfs de "waarden" binnen een bepaald bereik te kijken.

Waar u de structuur niet kunt wijzigen, is uw enige optie mapReduce. Hiermee kunt u het doorlopen van de sleutels "coderen", maar aangezien dit JavaScript-interpretatie en -uitvoering vereist, is het niet zo snel als het aggregatieraamwerk:

db.events.mapReduce(
    function() {
        emit(
            this.app_id,
            {
                "event_count": this.event_count,
                "event_count_per_type": this.event_count_per_type
            }
        );
    },
    function(key,values) {

        var reduced = { "event_count": 0, "event_count_per_type": {} };

        values.forEach(function(value) {
            for ( var k in value.event_count_per_type ) {
                if ( !redcuced.event_count_per_type.hasOwnProperty(k) )
                    reduced.event_count_per_type[k] = 0;
                reduced.event_count_per_type += value.event_count_per_type;
            }
            reduced.event_count += value.event_count;
        })
    },
    {
        "out": { "inline": 1 }
    }
)

Dat zal in wezen de "sleutels" doorkruisen en combineren en de waarden optellen voor elke gevonden sleutel.

Dus je opties zijn ofwel:

  1. Verander de structuur en werk met standaardquery's en aggregatie.
  2. Blijf bij de structuur en vereist JavaScript-verwerking en mapReduce.

Het hangt af van uw werkelijke behoeften, maar in de meeste gevallen levert herstructurering voordelen op.




  1. Selecteer geneste velden in mongo db

  2. Geheugencache versus Java-geheugen

  3. MongoDB-scherven implementeren en configureren met Ansible

  4. FindOne gebruiken in mongodb om element met max id te krijgen