MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Ordinamento per campo array massimo, crescente o decrescente

Il problema di base con ciò che stai chiedendo qui si riduce al fatto che i dati in questione si trovano all'interno di un "array", e quindi ci sono alcune ipotesi di base fatte da MongoDB su come questo viene gestito.

Se hai applicato un ordinamento in "ordine decrescente", MongoDB eseguirà esattamente ciò che chiedi e ordinerà i documenti in base al valore "più grande" del campo specificato all'interno dell'array:

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

Ma se invece ordini in ordine "crescente", ovviamente è vero il contrario e viene considerato il valore "più piccolo".

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

Quindi l'unico modo per farlo significa calcolare quale è la data massima dai dati nell'array e quindi ordinare in base a quel risultato. Ciò significa sostanzialmente applicare .aggregate() , che per meteor è un'operazione lato server, essendo purtroppo qualcosa del genere:

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

O al massimo con MongoDB 3.2, dove $max può essere applicato direttamente a un'espressione di matrice:

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

Ma in realtà entrambi non sono il massimo, anche se l'approccio MongoDB 3.2 ha un sovraccarico molto inferiore rispetto a quello disponibile per le versioni precedenti, non è comunque così buono come puoi ottenere in termini di prestazioni a causa della necessità di passare attraverso i dati e lavorare il valore su cui eseguire l'ordinamento.

Quindi per il meglio prestazioni, mantieni "sempre" i dati di cui avrai bisogno "fuori" dall'array. Per questo c'è il $max operatore "aggiorna", che sostituirà un valore all'interno del documento solo "se" il valore fornito è "maggiore di" il valore esistente già presente. cioè:

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

Ciò significa che il valore che desideri sarà "sempre" già presente all'interno del documento con il valore atteso, quindi è solo ora una semplice questione di ordinamento su quel campo:

.sort({ "maxDate": 1 })

Quindi, per i miei soldi, esaminerei i dati esistenti con uno dei .aggregate() istruzioni disponibili e utilizzare tali risultati per aggiornare ogni documento in modo che contenga un campo "maxDate". Quindi cambia la codifica di tutte le aggiunte e le revisioni dei dati dell'array per applicare quel $max "aggiorna" ad ogni modifica.

Avere un campo solido piuttosto che un calcolo ha sempre molto più senso se lo usi abbastanza spesso. E la manutenzione è abbastanza semplice.

In ogni caso, considerando la data di esempio applicata sopra, che è "inferiore" alle altre date massime presenti mi ritornerei in tutte le forme:

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

Che posiziona correttamente il primo documento all'inizio dell'ordinamento tenendo conto del "maxDate".