sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB sammanlagd summa varje nyckel på ett underdokument

Som nämnts är det inte möjligt att bearbeta dokument som detta med aggregeringsramverket om du inte faktiskt ska tillhandahålla alla nycklar, till exempel:

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 måste givetvis uttryckligen ange varje nyckel du vill arbeta med. Detta gäller både för aggregeringsramverket och allmänna frågeoperationer i MongoDB, eftersom du för att få åtkomst till element noterade i detta "underdokument"-formulär måste ange den "exakta sökvägen" till elementet för att kunna göra något med det.

Aggregeringsramverket och allmänna frågor har inget koncept av "traversal", vilket innebär att de inte kan behandla "varje nyckel" i ett dokument. Det kräver en språkkonstruktion för att göra det som inte finns i dessa gränssnitt.

Generellt sett är dock att använda ett "nyckelnamn" som en datapunkt där dess namn faktiskt representerar ett "värde" lite av ett "antimönster". Ett bättre sätt att modellera detta skulle vara att använda en array och representera din "typ" som ett värde för sig själv:

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

Notera också att "datumet" nu är ett riktigt datumobjekt snarare än en sträng, vilket också är något som är bra att göra. Denna typ av data är dock lätt att bearbeta med aggregeringsramverket:

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 visar en tvåstegsgruppering som först får totalsummorna per "typ" utan att ange varje "nyckel" eftersom du inte längre behöver det, och sedan returnerar som ett enda dokument per "app_id" med resultaten i en array som de ursprungligen lagrades. Detta dataformulär är i allmänhet mycket mer flexibelt för att titta på vissa "typer" eller till och med "värdena" inom ett visst intervall.

Om du inte kan ändra strukturen är ditt enda alternativ mapReduce. Detta låter dig "koda" genomgången av nycklarna, men eftersom detta kräver JavaScript-tolkning och exekvering är det inte lika snabbt som aggregeringsramverket:

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 kommer i huvudsak att gå igenom och kombinera "nycklarna" och summera värdena för var och en som hittas.

Så dina alternativ är antingen:

  1. Ändra strukturen och arbeta med standardfrågor och aggregering.
  2. Behåll strukturen och kräver JavaScript-bearbetning och mapReduce.

Det beror på dina faktiska behov, men i de flesta fall ger en omstrukturering fördelar.




  1. Redis cache vs att använda minne direkt

  2. Gruppera och räkna med kondition

  3. Vad är ett rent sätt att stoppa mongod på Mac OS X?

  4. Percona Live 2017 - Severalnines Recap