Documenti secondari di Mongoose vs schema nidificato


122

Sono curioso dei pro e dei contro dell'utilizzo di documenti secondari rispetto a uno strato più profondo nel mio schema principale:

var subDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [subDoc]
});

o

var mainDoc = new Schema({
  names: [{
    name: String
 }]
});

Attualmente sto utilizzando sottodoc ovunque, ma mi chiedo principalmente problemi di prestazioni o query che potrei incontrare.


Stavo cercando di risponderti, ma non sono riuscito a trovare come. Ma dai un'occhiata qui: mongoosejs.com/docs/subdocs.html
gustavohenke

Ecco una buona risposta sulle considerazioni MongoDB da porsi quando si crea lo schema del database: stackoverflow.com/questions/5373198/...
anthonylawson

Volevi dire che è obbligatorio descrivere anche il _idcampo? Voglio dire, non è abbastanza automatico se è abilitato?
Vadorequest

qualcuno sa se il _idcampo dei documenti secondari è unico? (creato utilizzando 2nd way nella domanda di OP)
Saitama

Risposte:


72

Secondo i documenti , è esattamente lo stesso. Tuttavia, l'utilizzo di uno schema aggiungerebbe anche un _idcampo (a condizione che non sia disabilitato) e presumibilmente utilizza alcune risorse in più per tenere traccia dei sottodoc.

Sintassi della dichiarazione alternativa

Novità nella v3 Se non hai bisogno di accedere all'istanza dello schema del documento secondario, puoi anche dichiarare i documenti secondari semplicemente passando un oggetto letterale [...]


1
Ma ho provato questo. Perché i dati dei documenti secondari non vengono archiviati in una raccolta separata. Memorizza sempre all'interno della raccolta mainDoc.
Fizer Khan

17
è così che funzionano i documenti secondari. si stanno incorporando all'interno di un documento. prima di giocare con la mangusta, assicurati di aver compreso il MongoDB sottostante.
AndyL

1
Per quanto riguarda lo schema che aggiunge _id, ha senso ma ho creato uno schema con un array di sottodocumenti e un array di letterali oggetto e un _id è stato aggiunto a entrambi. Il comportamento è cambiato?
Drew Goodwin

@DrewGoodwin sembra che sia stato così per un po ': stackoverflow.com/questions/17254008/…
cheesemacfly

37

Se hai schemi che vengono riutilizzati in varie parti del tuo modello, potrebbe essere utile definire schemi individuali per i documenti secondari in modo da non doverti duplicare.


4
Questa è un'ottima risposta. A volte utilizzo documenti secondari in più di un modello oppure ho due campi in un modello che devono essere distinti, ma hanno comunque la stessa struttura del documento secondario.
Martin Hallén

2
dovresti anche considerare i vantaggi / svantaggi del salvataggio di informazioni ridondanti.
Sam Vloeberghs

25

È necessario utilizzare documenti incorporati se si tratta di documenti statici o se non sono più di poche centinaia a causa dell'impatto sulle prestazioni. Ho affrontato questo problema per un po 'di tempo fa. Di recente, Asya Kamsky, che lavora come solution architect per MongoDB, ha scritto un articolo sull '"utilizzo di documenti secondari".

Spero che questo aiuti a chi cerca soluzioni o le migliori pratiche.

Post originale su http://askasya.com/post/largeembeddedarrays . Puoi raggiungere il suo profilo stackoverflow su https://stackoverflow.com/users/431012/asya-kamsky

Prima di tutto, dobbiamo considerare perché vorremmo fare una cosa del genere. Normalmente, consiglierei alle persone di incorporare cose che vogliono sempre recuperare quando scaricano questo documento. Il rovescio della medaglia è che non vuoi incorporare nel documento cose che non vuoi recuperare.

Se incorpori l'attività che eseguo nel documento, all'inizio funzionerà benissimo perché tutta la mia attività è proprio lì e con una singola lettura puoi recuperare tutto ciò che potresti volermi mostrare: "recentemente hai fatto clic su questo e qui sono i tuoi ultimi due commenti "ma cosa succede dopo sei mesi che passano e non mi interessano le cose che ho fatto molto tempo fa e non vuoi mostrarmele a meno che non vada espressamente a cercare qualche vecchia attività?

In primo luogo, finirai per restituire un documento sempre più grande e preoccuparti di porzioni sempre più piccole di esso. Ma puoi usare la proiezione per restituire solo una parte dell'array, il vero problema è che il documento su disco diventerà più grande e sarà comunque letto tutto anche se ne restituirai solo una parte all'utente finale, ma poiché la mia attività non si interromperà finché sarò attivo, il documento continuerà a crescere e crescere.

Il problema più ovvio con questo è che alla fine raggiungerai il limite di documenti di 16 MB, ma non è affatto quello di cui dovresti preoccuparti. Un documento in continua crescita comporterà costi sempre più elevati ogni volta che deve essere riposizionato su disco e, anche se si adottano misure per mitigare gli effetti della frammentazione, le scritture saranno complessivamente inutilmente lunghe, influendo sulle prestazioni complessive dell'intera applicazione.

C'è ancora una cosa che puoi fare per uccidere completamente le prestazioni della tua applicazione ed è indicizzare questo array in continua crescita. Ciò significa che ogni volta che il documento con questo array viene riposizionato, il numero di voci di indice che devono essere aggiornate è direttamente proporzionale al numero di valori indicizzati in quel documento e più grande è l'array, maggiore sarà il numero essere.

Non voglio che questo ti spaventi dall'usare gli array quando sono adatti per il modello di dati: sono una potente funzionalità del modello di dati del database dei documenti, ma come tutti i potenti strumenti, deve essere utilizzato nelle giuste circostanze e dovrebbe essere usato con cura.


3
Questa dovrebbe essere la risposta migliore; è il botto sui soldi. I white paper di MongoDB dicono più o meno la stessa cosa.
Jay Edwards

Questo articolo sul modello Bucket complimenta ciò di cui Asya parla piacevolmente. mongodb.com/blog/post/building-with-patterns-the-bucket-pattern Penso che lo schema subDoc nella domanda di OP funzionerebbe bene con il modello Bucket.
plong0

13

Fondamentalmente, crea una variabile nestedDove mettila quiname: [nestedDov]

Versione semplice:

var nestedDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [nestedDoc]
});

Esempio JSON

{
    "_id" : ObjectId("57c88bf5818e70007dc72e85"),
    "name" : "Corinthia Hotel Budapest",
    "stars" : 5,
    "description" : "The 5-star Corinthia Hotel Budapest on the Grand Boulevard offers free access to its Royal Spa",
    "photos" : [
        "/photos/hotel/corinthiahotelbudapest/1.jpg",
        "/photos/hotel/corinthiahotelbudapest/2.jpg"
    ],
    "currency" : "HUF",
    "rooms" : [
        {
            "type" : "Superior Double or Twin Room",
            "number" : 20,
            "description" : "These are some great rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/2.jpg",
                "/photos/room/corinthiahotelbudapest/5.jpg"
            ],
            "price" : 73000
        },
        {
            "type" : "Deluxe Double Room",
            "number" : 50,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 92000
        },
        {
            "type" : "Executive Double Room",
            "number" : 25,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 112000
        }
    ],
    "reviews" : [
        {
            "name" : "Tamas",
            "id" : "/user/tamas.json",
            "review" : "Great hotel",
            "rating" : 4
        }
    ],
    "services" : [
        "Room service",
        "Airport shuttle (surcharge)",
        "24-hour front desk",
        "Currency exchange",
        "Tour desk"
    ]
}

Esempio:

inserisci qui la descrizione dell'immagine


1
Questo non risolve affatto la questione che è una delle prestazioni.
cyberwombat

Ho modificato un po 'per dare più senso. Cosa ne pensi?
Wayne Chiu

3
La domanda non è chiedersi come fare schemi annidati. È una discussione sul fatto che Mongoose sia più performante con schemi annidati o sotto documenti incorporati. Fondamentalmente stiamo parlando di benchmark o tipi o casi limite in cui Mongoose preferisce l'uno all'altro. E come menziona la risposta selezionata, non sembra fare alcuna differenza, almeno dalla V3 in poi.
cyberwombat

17
Forse non funziona per l'OP, ma l'ho trovato molto utile. Grazie.
Gene Higgins

Questo è positivo quando tutti e 3 gli schemi sono dichiarati in un file .js, come possiamo gestirlo quando dichiarato in 3 diversi file .js?
Satyam

9

Penso che questo sia gestito altrove da più post su SO.

Solo alcune:

La chiave è che qui non esiste un'unica risposta, solo una serie di compromessi piuttosto complessi.


3
Forse non sto formulando correttamente la mia domanda - Questa non è una questione di come dovrei strutturare il mio database, ma piuttosto gli elementi interni dell'utilizzo di un sottoschema rispetto alla semplice scrittura dell'array in uno strato più profondo. La mia causa principale per l'utilizzo di uno schema secondario è che posso fare uso di tipi di schemi personalizzati e farli convalidare - qualcosa che non funziona con gli array annidati (da una domanda precedente che avevo su SO). Per quanto posso dire, un sottodoc è più o meno lo stesso di un array annidato - semplicemente non ne conosco gli interni - se il loro utilizzo creerebbe problemi di prestazioni o simili.
cyberwombat

0

Ci sono alcune differenze tra i due:

  • L'utilizzo di schemi nidificati è utile per la convalida.

  • Lo schema nidificato può essere riutilizzato in altri schemi.

  • Lo schema nidificato aggiunge il campo "_id" al documento secondario a meno che tu non abbia utilizzato "_id: false"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.