MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Dynamic Sticky Sorting dans Mongo pour une valeur ou une liste simple

Impossible de reproduire votre erreur, mais vous avez quelques "fautes de frappe" dans votre question, je ne peux donc pas être sûr de ce que vous avez réellement.

Mais en supposant que vous travaillez réellement avec MongoDB 2.6 ou supérieur, vous voulez probablement le $setIntersection ou $setIsSubset plutôt que $setUnion . Ces opérateurs impliquent le contenu "correspondant" du tableau auquel ils sont comparés, où $setUnion combine simplement le tableau fourni avec celui existant :

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

Dans les versions antérieures où vous n'avez pas ces set opérateurs vous utilisez simplement $unwind pour travailler avec le tableau, et le même type de $cond opération comme avant dans un $group pour tout remettre en place :

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
    }}
])

Mais vous étiez certainement sur la bonne voie. Choisissez simplement la bonne opération de réglage ou une autre méthode afin d'obtenir votre besoin précis.

Ou puisque vous avez posté votre façon d'obtenir ce que vous voulez, une meilleure façon d'écrire ce genre de "correspondance ordonnée" est la suivante :

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
    }}
])

Et cela donnerait la priorité aux documents avec des "offices" contenant "FL" sur "SC" et donc sur tous les autres, et faisant l'opération dans un seul champ. Cela devrait également être très facile pour les gens de voir comment résumer cela dans le formulaire en utilisant $unwind dans les versions antérieures sans les opérateurs d'ensemble. Où vous fournissez simplement la valeur de "poids" la plus élevée aux éléments que vous voulez en haut en imbriquant le $cond déclarations.