sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongo-fråga för att sortera efter distinkt antal

Detta hanteras verkligen (fortfarande) bäst av flera frågor, eftersom MongoDB verkligen "fortfarande" inte har de riktigt effektiva operatörerna för att göra detta ännu.

Du kan dock göra något liknande med MongoDB 3.2, men det finns uppenbara "fångster":

db.Books.aggregate([
    { "$group": {
        "_id": "$company",
        "count": { "$sum": 1 },
        "urls": {
            "$push": "$url"
        }
    }},
    { "$sort": { "count": -1 } },
    { "$limit": 10 },
    { "$project": {
        "count": 1,
        "urls": { "$slice": ["$urls",0, 3] }
    }}
])

Och det uppenbara problemet är att oavsett vad så lägger du fortfarande till alla av "url"-innehållet till den grupperade arrayen. Detta har potential att överskrida BSON-gränsen på 16 MB. Det kanske inte, men det är fortfarande lite slösaktigt att lägga till "allt" innehåll när du bara vill ha "tre" av dem.

Så även då är det förmodligen mer praktiskt att faktiskt fråga efter "webbadresserna" separat på vart och ett av de 10 bästa resultaten.

Här är en lista för node.js som visar:

var async = require('async'),
    mongodb = require('mongodb'),
    MongoClient = mongodb.MongoClient;

MongoClient.connect("mongodb://localhost/test",function(err,db) {

    if (err) throw err;

    // Get the top 10
    db.collection("Books").aggregate(
        [
            { "$group": {
                "_id": "$company",
                "count": { "$sum": 1 }
             }},
             { "$sort": { "count": -1 } },
             { "$limit": 10 }
        ],function(err,results) {
            if (err) throw err;

            // Query for each result and map query response as urls
            async.map(
                results,
                function(result,callback) {
                    db.collection("Books").find({ 
                       "company": result.company 
                    }).limit(3).toArray(function(err,items) {
                        result.urls = items.map(function(item) { 
                            return item.url;
                        });
                        callback(err,result);
                    })
                },
                function(err,results) {
                    if (err) throw err;
                    // each result entry has 3 urls
                }
            );
        }
     )

});

Ja, det är fler anrop till databasen, men det är verkligen bara tio och därför inte riktigt ett problem.

Det riktiga upplösning för detta täcks av SERVER-9377 - Förläng $push eller $max för att tillåta insamling av "top" " N värden per _id-nyckel i $group-fasen . Detta har den lovande statusen "Pågår", så det arbetas aktivt på det.

När det väl är löst blir en enstaka aggregeringssats genomförbar, eftersom du då skulle kunna "begränsa" de resulterande "webbadresserna" i den första $push till bara tre poster, istället för att ta bort alla utom tre i efterhand.




  1. Bästa modellen för att representera många till många relationer med attribut i MongoDB

  2. Använda $slice med $regex tillsammans på subDocument array i mongodb

  3. MongoDB - Fulltextindex - Fulltextsökning - stemming

  4. MongoDB Driver 2.0 C# finns det ett sätt att ta reda på om servern är nere? Hur kör vi Ping-kommandot i den nya drivrutinen?