Subdocumentos de Mongoose vs esquema aninhado


122

Estou curioso quanto aos prós e contras do uso de subdocumentos vs uma camada mais profunda no meu esquema principal:

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

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

ou

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

Atualmente, estou usando subdocs em todos os lugares, mas estou me perguntando principalmente sobre problemas de desempenho ou de consulta que possa encontrar.


Eu estava tentando digitar uma resposta para você, mas não consegui descobrir como. Mas dê uma olhada aqui: mongoosejs.com/docs/subdocs.html
gustavohenke

Aqui está uma boa resposta sobre considerações MongoDB perguntar a si mesmo ao criar o esquema do banco de dados: stackoverflow.com/questions/5373198/...
anthonylawson

Você quis dizer que é necessário também descrever o _idcampo? Quero dizer, não é meio automático se estiver ativado?
Vadorequest

Alguém sabe se o _idcampo dos subdocumentos é único? (criado usando segunda maneira em questão do OP)
Saitama

Respostas:


72

De acordo com os documentos , é exatamente o mesmo. No entanto, o uso de um esquema também adicionaria um _idcampo (desde que você não o tenha desativado) e, presumivelmente, usa mais alguns recursos para rastrear subdocs.

Sintaxe de declaração alternativa

Novo na v3 Se você não precisar acessar a instância do esquema de sub-documento, também poderá declarar sub-documentos, passando simplesmente um literal de objeto [...]


1
Mas eu tentei isso. Por que os dados dos sub-documentos não são armazenados em uma coleção separada. Ele sempre armazena dentro da coleção mainDoc.
Fizer Khan #: 27313

17
é assim que os sub-documentos funcionam. eles estão incorporando dentro de um documento. Antes de jogar com o mangusto, certifique-se de entender o MongoDB subjacente.
AndyL 31/05

1
Em relação ao esquema adicionando _id, isso faz sentido, mas eu criei um esquema com uma matriz de sub-documentos e uma matriz de literais de objetos e um _id foi adicionado a ambos. O comportamento mudou?
Drew Goodwin

@DrewGoodwin parece que tem sido assim por um tempo: stackoverflow.com/questions/17254008/...
cheesemacfly

37

Se você tiver esquemas reutilizados em várias partes do seu modelo, pode ser útil definir esquemas individuais para os documentos filhos, para que você não precise se duplicar.


4
Esta é uma ótima resposta. Às vezes, uso subdocumentos em mais de um modelo ou tenho dois campos em um modelo que precisam ser distinguidos, mas ainda possuem a mesma estrutura de subdocumento.
Martin Hallén

2
você também deve considerar os benefícios / desvantagens de salvar informações redundantes.
Sam Vloeberghs

25

Você deve usar documentos incorporados se forem documentos estáticos ou se não forem mais do que algumas centenas devido ao impacto no desempenho. Já discuti esse assunto há algum tempo. Recentemente, Asya Kamsky, que trabalha como arquiteto de soluções para o MongoDB, havia escrito um artigo sobre "usando subdocumentos".

Espero que ajude quem está procurando soluções ou as melhores práticas.

Post original em http://askasya.com/post/largeembeddedarrays . Você pode acessar seu perfil de stackoverflow em https://stackoverflow.com/users/431012/asya-kamsky

Primeiro de tudo, temos que considerar por que queremos fazer uma coisa dessas. Normalmente, eu aconselho as pessoas a incorporar coisas que eles sempre querem voltar quando estão buscando este documento. O outro lado disso é que você não deseja incorporar coisas no documento que não deseja voltar com ele.

Se você incorporar a atividade que eu realizo no documento, ele funcionará muito bem no início, porque toda a minha atividade está ali e, com uma única leitura, você pode recuperar tudo o que deseja me mostrar: "você clicou recentemente aqui e aqui são seus dois últimos comentários ", mas o que acontece depois de seis meses se passaram e eu não me importo com as coisas que fiz há muito tempo e você não quer mostrá-las, a menos que eu vá especificamente procurar alguma atividade antiga?

Primeiro, você retornará documentos cada vez maiores e se preocupará com cada vez menos partes dele. Mas você pode usar a projeção para retornar apenas parte da matriz. A verdadeira dor é que o documento no disco ficará maior e ainda será lido, mesmo se você só devolver parte dele ao usuário final, mas como minha atividade não será interrompida enquanto eu estiver ativo, o documento continuará crescendo e crescendo.

O problema mais óbvio disso é que, eventualmente, você atingirá o limite de 16 MB de documentos, mas não é com isso que você deve se preocupar. Um documento que cresce continuamente terá custos cada vez mais altos sempre que for realocado no disco e, mesmo que você tome medidas para reduzir os efeitos da fragmentação, suas gravações serão desnecessariamente longas, afetando o desempenho geral de todo o aplicativo.

Há mais uma coisa que você pode fazer que prejudica completamente o desempenho do seu aplicativo e é indexar essa matriz cada vez maior. O que isso significa é que, toda vez que o documento com essa matriz é realocado, o número de entradas de índice que precisam ser atualizadas é diretamente proporcional ao número de valores indexados nesse documento, e quanto maior a matriz, maior será o número. estar.

Não quero que isso o assuste de usar matrizes quando elas são adequadas para o modelo de dados - elas são um recurso poderoso do modelo de dados do banco de dados de documentos, mas, como todas as ferramentas poderosas, ele precisa ser usado nas circunstâncias certas e deve ser usado com cuidado.


3
Essa deve ser a resposta principal; é estrondo no dinheiro. Os white papers do MongoDB dizem praticamente a mesma coisa.
Jay Edwards

Este artigo sobre o padrão de balde complementa o que Asya fala bem. mongodb.com/blog/post/building-with-patterns-the-bucket-pattern Acho que o esquema subDoc na pergunta do OP funcionaria bem com o padrão de balde.
plong0

13

Basicamente, crie uma variável nestedDove coloque-a aquiname: [nestedDov]

Versão Simples:

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

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

Exemplo 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"
    ]
}

Exemplo:

insira a descrição da imagem aqui


1
Isso não aborda a questão de qual é o desempenho.
cyberwombat 02/09

Eu editei um pouco para fazer mais sentido. O que você acha?
Wayne Chiu

3
A questão não está perguntando como fazer esquemas aninhados. É uma discussão sobre se o Mongoose tem melhor desempenho com esquemas aninhados ou sub-documentos incorporados. Basicamente, estamos falando de benchmarks, tipos ou casos extremos onde o Mongoose prefere um ao outro. E como a resposta selecionada menciona, não parece fazer nenhuma diferença, pelo menos a partir da V3.
cyberwombat

17
Talvez não funcione para o OP, mas achei isso muito útil. Obrigado.
Gene Higgins

Isso é bom quando todos os 3 esquemas são declarados em um arquivo .js, como podemos lidar com isso quando declarados em 3 arquivos .js diferentes?
Satyam

9

Eu acho que isso é tratado em outro lugar por várias postagens no SO.

Apenas alguns:

A grande chave é que não há uma resposta única aqui, apenas um conjunto de compensações bastante complexas.


3
Talvez eu não esteja formulando minha pergunta corretamente - esta não é uma questão de como eu deveria estruturar meu banco de dados, mas sim os aspectos internos do uso de um sub-esquema versus apenas escrever a matriz em uma camada mais profunda. Minha principal causa para o uso de um sub-esquema é que posso fazer uso de tipos de esquema personalizados e validá-los - algo que não funciona com matrizes aninhadas (de uma pergunta anterior que fiz no SO). Tão perto quanto eu posso dizer que um subdoc é praticamente o mesmo que uma matriz aninhada - eu apenas não conheço os detalhes internos - se usá-los criaria problemas de desempenho ou algo assim.
cyberwombat

0

Há alguma diferença entre os dois:

  • O uso do esquema aninhado é útil para validação.

  • O esquema aninhado pode ser reutilizado em outros esquemas.

  • O esquema aninhado adiciona o campo '_id' ao subdocumento, a menos que você tenha usado "_id: false"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.