sql >> Database >  >> NoSQL >> MongoDB

Hoe kan ik met mongodb een aantal records per specifiek veld selecteren?

U kunt dit nog niet doen met het aggregatieraamwerk - u kunt de $max- of topdatumwaarde voor elke groep krijgen, maar het aggregatieraamwerk heeft nog geen manier om top N te verzamelen en er is geen manier om het hele document in de resultatenset te duwen (alleen individuele velden).

Je moet dus terugvallen op MapReduce. Hier is iets dat zou werken, maar ik weet zeker dat er veel varianten zijn (allemaal moet op de een of andere manier een reeks objecten worden gesorteerd op basis van een specifiek kenmerk, ik leende mijn oplossing van een van de antwoorden op deze vraag .

Kaartfunctie - voert de groepsnaam uit als een sleutel en de hele rest van het document als de waarde - maar het voert het uit als een document dat een array bevat omdat we zullen proberen een reeks resultaten per groep te verzamelen:

map = function () { 
    emit(this.name, {a:[this]}); 
}

De reduceerfunctie verzamelt alle documenten die tot dezelfde groep behoren in één array (via concat). Merk op dat als je reduce optimaliseert om alleen de top vijf array-elementen te behouden door de datum te controleren, je de finalize-functie niet nodig hebt en dat je minder geheugen gebruikt tijdens het uitvoeren van mapreduce (het zal ook sneller zijn).

reduce = function (key, values) {
    result={a:[]};
    values.forEach( function(v) {
        result.a = v.a.concat(result.a);
    } );
    return result;
}

Aangezien ik alle waarden voor elke sleutel bewaar, heb ik een finaliseringsfunctie nodig om slechts de laatste vijf elementen per sleutel te verkrijgen.

final = function (key, value) {
      Array.prototype.sortByProp = function(p){
       return this.sort(function(a,b){
       return (a[p] < b[p]) ? 1 : (a[p] > b[p]) ? -1 : 0;
      });
    }

    value.a.sortByProp('date');
    return value.a.slice(0,5);
}

Gebruikmakend van een sjabloondocument dat lijkt op het document dat u heeft verstrekt, voert u dit uit door de opdracht mapReduce aan te roepen:

> db.top5.mapReduce(map, reduce, {finalize:final, out:{inline:1}})
{
    "results" : [
        {
            "_id" : "group1",
            "value" : [
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe13"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.498Z"),
                    "contents" : 0.23778377776034176
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0e"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.467Z"),
                    "contents" : 0.4434165076818317
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe09"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.436Z"),
                    "contents" : 0.5935856597498059
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe04"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.405Z"),
                    "contents" : 0.3912118375301361
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfdff"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.372Z"),
                    "contents" : 0.221651989268139
                }
            ]
        },
        {
            "_id" : "group2",
            "value" : [
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe14"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.504Z"),
                    "contents" : 0.019611883210018277
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0f"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.473Z"),
                    "contents" : 0.5670706110540777
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0a"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.442Z"),
                    "contents" : 0.893193120136857
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe05"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.411Z"),
                    "contents" : 0.9496864483226091
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe00"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.378Z"),
                    "contents" : 0.013748752186074853
                }
            ]
        },
        {
            "_id" : "group3",
                        ...
                }
            ]
        }
    ],
    "timeMillis" : 15,
    "counts" : {
        "input" : 80,
        "emit" : 80,
        "reduce" : 5,
        "output" : 5
    },
    "ok" : 1,
}

Elk resultaat heeft _id als groepsnaam en waarden als array van de meest recente vijf documenten uit de collectie voor die groepsnaam.



  1. Apache HBase + Apache Hadoop + Xceivers

  2. Uitzondering krijgen tijdens het doen van block() op Mono-object Ik kreeg terug van ReactiveMongoRepository-object

  3. Kan het Accounts-Base-pakket niet naar de juiste database laten verwijzen

  4. Joins uitvoeren in mongodb met drie collecties?