sql >> Database teknologi >  >> NoSQL >> MongoDB

MongoDB Samlet sum af hver nøgle på et underdokument

Som nævnt er det ikke muligt at behandle dokumenter som dette med aggregeringsrammen, medmindre du rent faktisk skal levere alle nøglerne, såsom:

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

Men du skal selvfølgelig udtrykkeligt angive hver nøgle, du ønsker at arbejde på. Dette gælder både for aggregeringsrammerne og generelle forespørgselsoperationer i MongoDB, da du for at få adgang til elementer noteret i denne "underdokument"-form skal angive den "nøjagtige sti" til elementet for at kunne gøre noget med det.

Aggregeringsrammen og generelle forespørgsler har intet begreb om "gennemgang", hvilket betyder, at de ikke kan behandle "hver nøgle" af et dokument. Det kræver en sprogkonstruktion for at kunne gøre det, som ikke findes i disse grænseflader.

Generelt set er det dog lidt af et "anti-mønster" at bruge et "nøglenavn" som et datapunkt, hvor dets navn faktisk repræsenterer en "værdi". En bedre måde at modellere dette på ville være at bruge et array og repræsentere din "type" som en værdi for sig selv:

{
    "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 }
    ]
}

Bemærk også, at "datoen" nu er et ordentligt datoobjekt frem for en streng, hvilket også er en god praksis at gøre. Denne slags data er dog nemme at behandle med aggregeringsrammen:

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

Det viser en totrinsgruppering, der først får totalerne pr. "type" uden at specificere hver "nøgle", da du ikke længere behøver det, og derefter returnerer som et enkelt dokument pr. "app_id" med resultaterne i et array, som de oprindeligt blev gemt. Denne dataformular er generelt meget mere fleksibel til at se på bestemte "typer" eller endda "værdier" inden for et bestemt område.

Hvor du ikke kan ændre strukturen, er din eneste mulighed mapReduce. Dette giver dig mulighed for at "kode" gennemgangen af ​​nøglerne, men da dette kræver JavaScript-fortolkning og udførelse er det ikke så hurtigt som aggregeringsrammen:

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

Det vil i det væsentlige krydse og kombinere "nøglerne" og opsummere værdierne for hver fundet.

Så dine muligheder er enten:

  1. Ændre strukturen og arbejde med standardforespørgsler og aggregering.
  2. Bliv ved strukturen og kræve JavaScript-behandling og kortReducer.

Det afhænger af dine faktiske behov, men i de fleste tilfælde giver omstrukturering fordele.




  1. Brug jedis hvordan man skriver til en specifik slot/node i redis cluster

  2. Batchindsættelse/opdatering ved hjælp af Mongoid?

  3. MongoDB:Hvordan opdaterer man flere dokumenter med en enkelt kommando?

  4. Formater et tal som valuta i SQL