2010-09-15 6 views
6

Link avere uno o più tag, quindi in un primo momento potrebbe sembrare naturale per incorporare i tag:Come implementeresti queste query in modo efficiente in MongoDB?

link = { title: 'How would you implement these queries efficiently in MongoDB?' 
     url: 'http://stackoverflow.com/questions/3720972' 
     tags: ['ruby', 'mongodb', 'database-schema', 'database-design', 'nosql']} 

Come sarebbe queste query essere attuate in modo efficiente?

  • link ottenere che contengono uno o più dato tag (per la ricerca di legami con dati tag)
  • ottenere un elenco di tutti i tag senza ripetizione (per la ricerca di dialogo completamento automatico)
  • ottenere i tag più popolari (per visualizzare i 10 tag o una tag cloud)

l'idea di rappresentare il link di cui sopra è basato sul MongoNY presentation, far scorrere 38.

risposta

4

ottenere i link che contengono tag "valore" :

db.col.find({tags: "value"}); 

link ottenere che contengono "val1", "val2" tag:

db.col.find({tags: { $all : [ "val1", "val2" ] }}); 

lista Get di tutti i tag senza ripetizione:

db.col.distinct("tags"); 

Ottenere i tag più popolari - questo non è qualcosa che può essere interrogato su un db esistente, quello che devi fare è aggiungere un campo di popolarità aggiornarlo ogni volta che una query recupera il documento, quindi eseguire una query con il campo di ordinamento impostato sulla popolarità.

Aggiornamento: soluzione proposta per funzionalità di popolarità. Prova ad aggiungere la seguente collezione, chiamiamola tag.

doc = {tag: String, pop: Integer}

ora una volta che si fa una query si raccolgono tutti i tag che sono stati mostrati (questi possono essere aggregati e fatto in modo asincrono) Quindi diciamo che si finisce con il seguenti tag: "tag1", "tag2", "tag3".

È quindi chiama il metodo di aggiornamento e incrementare il valore del campo pop:

db.tags.update({tag: { $in: ["tag1", "tag2", "tag3"] }}, { $inc: { pop: 1 }}); 
+0

Per aggiungere un campo popolarità per un tag, il tag avrebbe bisogno di essere aggiunti o spostati in una raccolta differenziata, corretta? – randomguy

+0

non è necessario, puoi tenerlo nella stessa collezione e usare solo un dbref per puntare al tag. una collezione diversa renderà più semplice la gestione dei dati (che è ciò che raccomando). – Asaf

+0

Nella raccolta di tag suggerirei di inserire il nome del tag nel campo _id piuttosto che utilizzare un campo tag separato. Inoltre, se non ti interessa fare un aggiornamento per tag piuttosto che usare $ in, puoi creare la query solo {_id: "tag_name"} e utilizzare la funzione upsert per creare nuove voci di tag. – mstearn

0

È inoltre possibile utilizzare $ addToSet per cambiare la matrice tag invece di $ spinta. Questo non modifica il documento quando il tag esiste già. Questo sarà un po 'più efficiente se si modificano i tag frequentemente (poiché i documenti non aumenteranno di molto). Ecco un esempio:

> db.tst_tags.remove() 
> db.tst_tags.update({'name':'test'},{'$addToSet':{'tags':'tag1'}}, true) 
> db.tst_tags.update({'name':'test'},{'$addToSet':{'tags':'tag1'}}, true) 
> db.tst_tags.update({'name':'test'},{'$addToSet':{'tags':'tag2'}}, true) 
> db.tst_tags.update({'name':'test'},{'$addToSet':{'tags':'tag2'}}, true) 
> db.tst_tags.update({'name':'test'},{'$addToSet':{'tags':'tag3'}}, true) 
> db.tst_tags.find() 
{ "_id" : ObjectId("4ce244548736000000003c6f"), "name" : "test", 
    "tags" : [ "tag1", "tag2", "tag3" ] }