MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Sortieren nach maximalem Array-Feld, aufsteigend oder absteigend

Das grundlegende Problem mit dem, was Sie hier fragen, beruht auf der Tatsache, dass sich die fraglichen Daten in einem "Array" befinden, und daher gibt es einige grundlegende Annahmen von MongoDB, wie dies gehandhabt wird.

Wenn Sie eine Sortierung in „absteigender Reihenfolge“ angewendet haben, wird MongoDB genau das tun, was Sie verlangen, und die Dokumente nach dem „größten“ Wert des angegebenen Felds innerhalb des Arrays sortieren:

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

Aber wenn Sie stattdessen "aufsteigend" sortieren, dann gilt natürlich das Gegenteil und der "kleinste" Wert wird berücksichtigt.

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

Die einzige Möglichkeit, dies zu tun, besteht darin, aus den Daten im Array herauszufinden, welches das maximale Datum ist, und dann nach diesem Ergebnis zu sortieren. Dies bedeutet im Wesentlichen die Anwendung von .aggregate() , was für meteor eine serverseitige Operation ist, die leider ungefähr so ​​​​aussieht:

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

Oder am besten mit MongoDB 3.2, wobei $max kann direkt auf einen Array-Ausdruck angewendet werden:

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

Aber wirklich beide sind nicht so toll, auch wenn der MongoDB 3.2-Ansatz viel weniger Overhead hat als das, was in früheren Versionen verfügbar ist, ist er immer noch nicht so gut, wie Sie in Bezug auf die Leistung erreichen können, da die Daten und die Arbeit weitergeleitet werden müssen out den Wert, nach dem sortiert werden soll.

Also zum Besten Leistung, halten Sie solche Daten, die Sie benötigen, "immer" "außerhalb" des Arrays. Dafür gibt es den $max "update"-Operator, der einen Wert innerhalb des Dokuments nur dann ersetzt, "wenn" der bereitgestellte Wert "größer als" der bereits vorhandene Wert ist. d.h.:

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

Das bedeutet, dass der gewünschte Wert "immer" bereits im Dokument mit dem erwarteten Wert vorhanden ist, sodass es jetzt nur noch eine Frage des Sortierens nach diesem Feld ist:

.sort({ "maxDate": 1 })

Für mein Geld würde ich also die vorhandenen Daten mit einem der .aggregate() durchgehen verfügbaren Anweisungen und verwenden Sie diese Ergebnisse, um jedes Dokument so zu aktualisieren, dass es ein "maxDate"-Feld enthält. Ändern Sie dann die Codierung aller Hinzufügungen und Überarbeitungen von Array-Daten, um diesen $max anzuwenden "Update" bei jeder Änderung.

Ein solides Feld anstelle einer Berechnung zu haben, ist immer viel sinnvoller, wenn Sie es oft genug verwenden. Und die Wartung ist ganz einfach.

Unter Berücksichtigung des oben angewendeten Beispieldatums, das "weniger als" die anderen vorhandenen maximalen Datumsangaben ist, würde sich für mich jedenfalls in allen Formen ergeben:

{
        "_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")
}

Womit das erste Dokument unter Berücksichtigung des "maxDate" korrekterweise ganz oben in der Sortierreihenfolge platziert wird.