MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Dynamic Sticky Sorting no Mongo para um valor ou lista simples


Não é possível reproduzir seu erro, mas você tem alguns "erros de digitação" em sua pergunta, então não posso ter certeza do que você realmente tem.

Mas, presumindo que você realmente esteja trabalhando com o MongoDB 2.6 ou superior, provavelmente deseja o $setIntersection ou $setIsSubset operadores em vez de $setUnion . Esses operadores implicam o conteúdo "correspondente" do array com o qual são comparados, onde $setUnion apenas combina a matriz fornecida com a existente:
db.people.aggregate([
    { "$project": {
        "first_name": 1,
        "last_name": 1,
        "sticky": { 
            "$size": { 
                "$setIntersection": [ "$offices", [ "FL", "SC" ]] 
            }
        },
        "offices": 1
    }},
    { "$sort": {
        "sticky": -1,
        "last_name": 1
    }}
])

Nas versões anteriores em que você não tem esses operadores de conjunto você está apenas usando $unwind para trabalhar com a matriz e o mesmo tipo de $cond operação como antes dentro de um $group para trazer tudo de volta:
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
    }}
])

Mas você certamente estava no caminho certo. Basta escolher a operação de conjunto correta ou outro método para obter sua necessidade precisa.

Ou desde que você postou sua maneira de obter o que deseja, uma maneira melhor de escrever esse tipo de "correspondência ordenada" é esta:
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
    }}
])

E isso daria prioridade a documentos com "escritórios" contendo "FL" sobre "SC" e, portanto, sobre todos os outros, e fazendo a operação dentro de um único campo. Isso também deve ser muito fácil para as pessoas verem como abstrair isso no formulário usando $unwind em versões anteriores sem os operadores de conjunto. Onde você simplesmente fornece o valor de "peso" mais alto para os itens que deseja no topo, aninhando o $cond declarações.