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

Il modo più efficiente per archiviare categorie nidificate (o dati gerarchici) in Mongo?

La prima cosa che vuoi decidere è esattamente che tipo di albero utilizzerai.

La cosa importante da considerare sono i tuoi dati e i modelli di accesso. Hai già affermato che il 90% di tutto il tuo lavoro verrà sottoposto a query e, a quanto pare, gli aggiornamenti (e-commerce) verranno eseguiti solo dagli amministratori, molto probabilmente raramente.

Quindi vuoi uno schema che ti dia il potere di interrogare rapidamente il bambino attraverso un percorso, ad esempio:Sport -> Basket -> Uomo, Sport -> Tennis -> Donna, e non ha davvero bisogno di ridimensionarsi per gli aggiornamenti.

Come hai giustamente sottolineato, MongoDB ha una buona pagina di documentazione per questo:https://docs.mongodb.com/manual/applications/data-models-tree-structures/ per cui 10gen in realtà stabilisce diversi modelli e metodi di schema per gli alberi e ne descrive i principali alti e bassi.

Quello che dovrebbe attirare l'attenzione se stai cercando di interrogare facilmente sono i percorsi materializzati:https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/

Questo è un metodo molto interessante per costruire alberi poiché per interrogare l'esempio che hai dato sopra in "Womens" in "Tennis" potresti semplicemente fare una regex prefissata (che può usare l'indice:http://docs.mongodb.org/manual/reference/operator/regex/ ) così:

db.products.find({category: /^Sports,Tennis,Womens[,]/})

per trovare tutti i prodotti elencati sotto un determinato percorso del tuo albero.

Sfortunatamente questo modello è davvero pessimo nell'aggiornamento, se sposti una categoria o ne cambi il nome devi aggiornare tutti i prodotti e potrebbero esserci migliaia di prodotti in una categoria.

Un metodo migliore sarebbe quello di ospitare un cat_id sul prodotto e poi separare le categorie in una raccolta separata con lo schema:

{
    _id: ObjectId(),
    name: 'Women\'s',
    path: 'Sports,Tennis,Womens',
    normed_name: 'all_special_chars_and_spaces_and_case_senstive_letters_taken_out_like_this'
}

Quindi ora le tue query riguardano solo la raccolta di categorie che dovrebbe renderle molto più piccole e più performanti. L'eccezione è che quando elimini una categoria, i prodotti dovranno comunque essere toccati.

Quindi un esempio di come cambiare "Tennis" in "Badmin":

db.categories.update({path:/^Sports,Tennis[,]/}).forEach(function(doc){
    doc.path = doc.path.replace(/,Tennis/, ",Badmin");
    db.categories.save(doc);
});

Sfortunatamente MongoDB al momento non fornisce alcuna riflessione sui documenti nella query, quindi è necessario estrarli dal lato client, il che è un po' fastidioso, tuttavia si spera che non debbano essere ripristinate troppe categorie.

E questo è fondamentalmente come funziona davvero. È un po' una seccatura aggiornare, ma credo che il potere di essere in grado di eseguire query istantaneamente su qualsiasi percorso utilizzando un indice sia più adatto al tuo scenario.

Naturalmente il vantaggio aggiuntivo è che questo schema è compatibile con i modelli di insiemi nidificati:http://en.wikipedia .org/wiki/Nested_set_model che ho scoperto più e più volte sono semplicemente fantastici per i siti di e-commerce, ad esempio, il tennis potrebbe essere sia in "Sport" che in "Tempo libero" e desideri più percorsi a seconda della provenienza dell'utente.

Lo schema per i percorsi materializzati lo supporta facilmente semplicemente aggiungendo un altro path , così semplice.

Spero che abbia senso, è piuttosto lungo lì.