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

Dynamische Sticky-Sortierung in Mongo für einen einfachen Wert oder eine Liste

Ich kann Ihren Fehler nicht reproduzieren, aber Sie haben ein paar "Tippfehler" in Ihrer Frage, daher kann ich nicht sicher sein, was Sie tatsächlich haben.

Aber vorausgesetzt, Sie arbeiten tatsächlich mit MongoDB 2.6 oder höher, dann möchten Sie wahrscheinlich den $setIntersection oder $setIsSubset Operatoren statt $setUnion . Diese Operatoren implizieren "übereinstimmende" Inhalte des Arrays, mit dem sie verglichen werden, wobei $setUnion kombiniert einfach das gelieferte Array mit dem bestehenden:

db.people.aggregate([
    { "$project": {
        "first_name": 1,
        "last_name": 1,
        "sticky": { 
            "$size": { 
                "$setIntersection": [ "$offices", [ "FL", "SC" ]] 
            }
        },
        "offices": 1
    }},
    { "$sort": {
        "sticky": -1,
        "last_name": 1
    }}
])

In früheren Versionen, in denen Sie diese Set-Operatoren nicht haben Sie verwenden nur $unwind um mit dem Array zu arbeiten, und die gleiche Art von $cond Vorgang wie zuvor innerhalb einer $group um alles wieder zusammenzubringen:

db.people.aggregate([
    { "$unwind": "$offices" },
    { "$group": {
        "_id": "$_id",
        "first_name": { "$first": "$first_name" },
        "last_name": { "$first": "$last_name",
        "sticky": { "$sum": { "$cond": [
            { "$or": [
                { "$eq": [ "$offices": "FL" ] },
                { "$eq": [ "$offices": "SC" ] },
            ]},
            1,
            0
        ]}},
        "offices": { "$push": "$offices" }
    }},
    { "$sort": {
        "sticky": -1,
        "last_name": 1
    }}
])

Aber Sie waren sicherlich auf dem richtigen Weg. Wählen Sie einfach die richtige Set-Operation oder andere Methode, um Ihren genauen Bedarf zu decken.

Oder da Sie Ihren Weg gepostet haben, was Sie wollen, ist eine bessere Möglichkeit, diese Art von "geordnetem Abgleich" zu schreiben:

db.people.aggregate([
    { "$project": {
        "first_name": 1,
        "last_name": 1,
        "sticky": { "$cond": [
            { "$anyElementTrue": {
                "$map": {
                    "input": "$offices",
                    "as": "o",
                    "in": { "$eq": [ "$$o", "FL" ] }
                }
            }},
            2,
            { "$cond": [
                { "$anyElementTrue": {
                    "$map": {
                        "input": "$offices",
                        "as": "o",
                        "in": { "$eq": [ "$$o", "SC" ] }
                    }
                }},
                1,
                0
            ]}
        ]},
        "offices": 1
    }},
    { "$sort": {
        "sticky": -1,
        "last_name": 1
    }}
])

Und das würde Dokumenten mit "Büros", die "FL" enthalten, Vorrang vor "SC" und damit dann vor allen anderen geben und die Operation in einem einzigen Feld ausführen. Das sollte auch für die Leute sehr einfach zu sehen sein, wie man das mit $unwind in früheren Versionen ohne die Set-Operatoren. Dabei geben Sie einfach den höheren "Gewichtswert" für die Elemente an, die Sie oben haben möchten, indem Sie $cond Aussagen.