sql >> Databasteknik >  >> NoSQL >> MongoDB

Sortering efter maximalt matrisfält, stigande eller fallande

Det grundläggande problemet med det du frågar här beror på det faktum att informationen i fråga är inom en "array", och därför finns det några grundläggande antaganden från MongoDB om hur detta hanteras.

Om du tillämpade en sortering i "fallande ordning", kommer MongoDB att göra exakt vad du ber om och sortera dokumenten efter det "största" värdet i det angivna fältet inom arrayen:

.sort({ "revisions.created": -1 ))

Men om du istället sorterar i "stigande" ordning så är naturligtvis det omvända sant och det "minsta" värdet beaktas.

.sort({ "revisions.created": 1 })

Så det enda sättet att göra detta innebär att räkna ut vilket som är det maximala datumet från data i arrayen och sedan sortera på det resultatet. Detta innebär i grunden att tillämpa .aggregate() , som för meteor är en operation på serversidan, som tyvärr är något sånt här:

Collection.aggregate([
    { "$unwind": "$revisions" },
    { "$group": {
        "_id": "$_id",
        "name": { "$first": "$name" },
        "revisions": { "$push": "$revisions" },
        "number": { "$first": "$number" }
        "maxDate": { "$max": "$revisions.created" }
    }},
    { "$sort": { "maxDate": 1 }
])

Eller i bästa fall med MongoDB 3.2, där $max kan appliceras direkt på ett arrayuttryck:

Collection.aggregate([
    { "$project": {
        "name": 1,
        "revisions": 1,
        "number": 1,
        "maxDate": {
            "$max": {
                "$map": {
                    "input": "$revisions",
                    "as": "el",
                    "in": "$$el.created"
                }
            }
        }
    }},
    { "$sort": { "maxDate": 1 } }
])

Men båda är egentligen inte så bra, även om MongoDB 3.2-metoden har mycket mindre omkostnader än vad som är tillgängligt för tidigare versioner, är det fortfarande inte så bra som du kan få när det gäller prestanda på grund av behovet av att passera igenom data och arbete ut värdet att sortera på.

Så för bästa prestanda, "alltid" behåll sådan data som du kommer att behöva "utanför" av arrayen. För detta finns $max "update" operator, som bara kommer att ersätta ett värde i dokumentet "om" det angivna värdet är "större än" det befintliga värdet som redan finns där. dvs:

Collection.update(
    { "_id": "qTF8kEphNoB3eTNRA" },
    { 
        "$push": {
            "revisions": { "created": new Date("2016-02-01") }            
        },
        "$max": { "maxDate": new Date("2016-02-01") }
    }
)

Det betyder att värdet du vill ha "alltid" redan finns i dokumentet med det förväntade värdet, så det är bara nu en enkel fråga att sortera på det fältet:

.sort({ "maxDate": 1 })

Så för mina pengar skulle jag gå igenom befintlig data med någon av .aggregate() tillgängliga uttalanden och använd dessa resultat för att uppdatera varje dokument så att det innehåller ett "maxDate"-fält. Ändra sedan kodningen för alla tillägg och revisioner av arraydata för att tillämpa den $max "uppdatering" vid varje ändring.

Att ha ett solidt fält snarare än en beräkning är alltid mycket mer meningsfullt om du använder det tillräckligt ofta. Och underhållet är ganska enkelt.

I vilket fall som helst, med tanke på ovan tillämpade exempeldatum, som är "mindre än" de andra maximala datumen som finns skulle återkomma för mig i alla former:

{
        "_id" : "5xF9iDTj3reLDKNHh",
        "name" : "Lorem ipsum",
        "revisions" : [
                {
                        "number" : 0,
                        "comment" : "Dolor sit amet",
                        "created" : ISODate("2016-02-11T01:22:45.588Z")
                }
        ],
        "number" : 1,
        "maxDate" : ISODate("2016-02-11T01:22:45.588Z")
}
{
        "_id" : "qTF8kEphNoB3eTNRA",
        "name" : "Consecitur quinam",
        "revisions" : [
                {
                        "comment" : "Hoste ad poderiquem",
                        "number" : 1,
                        "created" : ISODate("2016-02-11T23:25:46.033Z")
                },
                {
                        "number" : 0,
                        "comment" : "Fagor questibilus",
                        "created" : ISODate("2016-02-11T01:22:45.588Z")
                },
                {
                        "created" : ISODate("2016-02-01T00:00:00Z")
                }
        ],
        "number" : 2,
        "maxDate" : ISODate("2016-02-11T23:25:46.033Z")
}

Vilket korrekt placerar det första dokumentet högst upp i sorteringsordningen med hänsyn till "maxDatum".




  1. Dynamiska nycklar efter $group by

  2. MongoDB-servern kan fortfarande nås utan inloggningsuppgifter

  3. Hur söker jag efter strängar i redis?

  4. Frågar du MongoDB GridFS?