sql >> Database >  >> NoSQL >> MongoDB

Verbeteringen in MongoDB 2.6 Aggregation Framework

Dit is een gastpost van Vlad Mihalcea. Vlad is een software-architect met een passie voor software-integratie, hoge schaalbaarheid en uitdagingen op het gebied van gelijktijdigheid. Hier is een link naar het originele bericht.

MongoDB evolueert snel. De 2.2-versie introduceerde het aggregatieframework als alternatief voor het Map-Reduce-querymodel. Het genereren van geaggregeerde rapporten is een terugkerende vereiste voor bedrijfssystemen en MongoDB schittert in dit opzicht. Als dit nieuw voor u is, kunt u deze introductie van het aggregatieraamwerk of de prestatieafstemming en de handleidingen voor gegevensmodellering bekijken.

Laten we het datamodel hergebruiken dat ik voor het eerst heb geïntroduceerd terwijl ik de razendsnelle MongoDB-invoegmogelijkheden demonstreerde:

{
        "_id" : ObjectId("5298a5a03b3f4220588fe57c"),
        "created_on" : ISODate("2012-04-22T01:09:53Z"),
        "value" : 0.1647851116706831
}

MongoDB 2.6 Aggregatieverbeteringen

In de 2.4-versie, als ik de volgende aggregatiequery uitvoer:

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}]);

Ik heb de beperking van het aggregatieresultaat van 16 MB bereikt:

{
    "errmsg" : "exception: aggregation result exceeds maximum document size (16MB)",
    "code" : 16389,
    "ok" : 0
}

MongoDB-documenten zijn beperkt tot 16 MB en vóór versie 2.6 was het aggregatieresultaat een BSON-document. De versie 2.6 heeft het in plaats daarvan vervangen door een cursor.

Het uitvoeren van dezelfde zoekopdracht op 2.6 levert het volgende resultaat op:

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}])
.objsLeftInBatch();
14

Ik heb de cursorgebaseerde objsLeftInBatch-methode gebruikt om het type aggregatieresultaat te testen en de beperking van 16 MB is niet langer van toepassing op het algehele resultaat. De interne resultaten van de cursor zijn gewone BSON-documenten, daarom zijn ze nog steeds beperkt tot 16 MB, maar dit is veel beter beheersbaar dan de vorige algemene resultaatlimiet.

De 2.6-versie lost ook de beperkingen van het aggregatiegeheugen op. Een volledige collectiescan zoals:

db.randomData.aggregate( [
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}])
.objsLeftInBatch();

kan eindigen met de volgende fout:

{
    "errmsg" : "exception: Exceeded memory limit for $group, but didn't allow external sort. Pass allowDiskUse:true to opt in.",
    "code" : 16945,
    "ok" : 0
}

We kunnen nu dus grote sorteerbewerkingen uitvoeren met de parameter allowDiskUse:

db.randomData.aggregate( [
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
}]
,
{
    allowDiskUse : true
})
.objsLeftInBatch();

Met versie 2.6 kunnen we het aggregatieresultaat opslaan in een andere verzameling met behulp van de nieuw toegevoegde fase $out.

db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 10))
        }
    }
},
{
    $group: {
        _id : {
            "minute" : {
                $minute : "$created_on"
            }
        },
        "values": {
            $addToSet: "$value"
        }
    }
},
{
    $out : "randomAggregates"
}
]);
db.randomAggregates.count();
60

Er zijn nieuwe operators toegevoegd, zoals let, map, cond, om er maar een paar te noemen.

In het volgende voorbeeld wordt AM of PM toegevoegd aan de tijdinformatie van elke specifieke gebeurtenisinvoer.

var dataSet = db.randomData.aggregate( [
{
    $match: {
        "created_on" : {
            $gte : new Date(Date.UTC(2012, 0, 1)),
            $lte : new Date(Date.UTC(2012, 0, 2))
        }
    }
},
{
    $project: {
        "clock" : {
            $let: {
                vars: {
                    "hour": {
                        $substr: ["$created_on", 11, -1]
                    },
                    "am_pm": { $cond: { if: { $lt: [ {$hour : "$created_on" }, 12 ] } , then: 'AM',else: 'PM'} }
                },
                in: { $concat: [ "$$hour", " ", "$$am_pm"] }
            }
        }
    }
},
{
    $limit : 10
}
]);
dataSet.forEach(function(document)  {
    printjson(document);
});

Resulterend in:

"clock" : "16:07:14 PM"
"clock" : "22:14:42 PM"
"clock" : "21:46:12 PM"
"clock" : "03:35:00 AM"
"clock" : "04:14:20 AM"
"clock" : "03:41:39 AM"
"clock" : "17:08:35 PM"
"clock" : "18:44:02 PM"
"clock" : "19:36:07 PM"
"clock" : "07:37:55 AM"

Conclusie

MongoDB 2.6-versie wordt geleverd met veel andere verbeteringen, zoals bulkbewerkingen of indexkruising. MongoDB evolueert voortdurend en biedt een levensvatbaar alternatief voor op documenten gebaseerde opslag. Met zo'n ontwikkelingstempo is het geen wonder dat het de database van het jaar 2013 werd.


  1. Sleutels zoeken met jokertekens

  2. Mongodb-telling verschillend met meerdere groepsvelden

  3. Mongoose String naar ObjectID

  4. Redis gebruiken als tussencache voor REST API