MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

correspondência de estrutura de agregação mongodb por documentos aninhados


Consultar essa estrutura para obter os resultados desejados não é possível sem conhecer todos os forms possíveis nomes de antemão e usá-los na consulta. Seria muito confuso de qualquer forma. Dito isso, continue lendo enquanto explico como isso pode ser feito.

Há um problema com a estrutura desses documentos que impedirá que você faça qualquer análise de consulta razoável. Tal como está, você teria que conhecer todos os campos de nome de formulário possíveis para filtrar qualquer coisa.

Sua estrutura atual tem formulários contendo um subdocumento, cada chave contém outro subdocumento com uma única propriedade, status . Isso é difícil de percorrer, pois seus forms elemento tem uma estrutura arbitrária para cada documento que você cria. Isso significa que o padrão descer para o status informações que você deseja comparar as alterações para cada documento em sua coleção.

Aqui está o que quero dizer com caminho. Para obter o status em qualquer elemento, você deve fazer o seguinte

Com o segundo elemento mudando o tempo todo. Não há nenhuma maneira para curinga algo assim, pois a nomenclatura é considerada explícita.

Isso pode ter sido considerado uma maneira fácil de implementar a serialização dos dados de seus formulários mas vejo um mais flexível alternativo. O que você precisa é de uma estrutura de documento que você possa percorrer em um padrão padrão. Isso é sempre algo que vale a pena considerar no design. Tome o seguinte:
{
    "_id" : "Tvq444454j",
    "name": "Jim",
    "forms": [
        {
             "name": "Jorney",
             "status":"closed"          
        },
        {
            "name": "Women",
            "status":"void"            
        },
        {
            "name": "Child",
            "status":"closed"           
        },
        {
            "name": "Farm",
            "status":"closed"            
        }  
    ]
}

Assim, a estrutura do documento é alterada para tornar os forms elemento um Array, e em vez de colocar o campo de status sob uma chave que nomeia o "campo de formulário", temos cada membro do Array como um subdocumento contendo o "campo de formulário" name e o status . Portanto, tanto o identificador quanto o status ainda estão emparelhados, mas agora apenas representados como um subdocumento. Isso mais importante altera o caminho de acesso a essas chaves, como agora para ambos o nome do campo e seu status podemos fazer

O que isto significa é que você pode consultar para encontrar os nomes de todos os campos no form ou todos os status campos no form , ou mesmo todos os documentos com um determinado name campo e determinado status . Isso é muito melhor do que o que poderia ser feito com a estrutura original.

Agora, no seu caso específico, você deseja obter somente os documentos onde todos os campos não são void . Agora não há como fazer isso em uma única consulta, pois não há operador para comparar todos os elementos em uma matriz dessa maneira e ver se eles são os mesmos. Mas há duas abordagens que você pode adotar:

A primeira e provavelmente não tão eficiente é consultar todos documentos que contêm um elemento em forms que tem um status de "vazio". Com os IDs de documentos resultantes, você pode emitir outra consulta que retorne os documentos que não tem os Id's que foram especificados.
db.forms.find({ "forms.status": "void" },{ _id: 1})

db.forms.find({ _id: $not: { $in: [<Object1>,<Object2>,<Object3>,... ] } })

Dado o tamanho do resultado, isso pode não ser possível e geralmente não é uma boa ideia, pois o operador de exclusão $not está basicamente forçando uma varredura completa da coleção, então você não pode usar um índice.

Outra abordagem é usar o pipeline de agregação da seguinte maneira:
db.forms.aggregate([
    { "$unwind": "$forms" },
    { "$group": { "_id": "$_id", "status": { "$addToSet": "$forms.status" }}},
    { "$unwind": "$status" },
    { "$sort": { "_id": 1, "status": -1 }},
    { "$group": { "_id": "$_id", "status": { "$first": "$status"}}},
    { "$match":{ "status": "closed" }}
])

É claro que isso retornará apenas o _id para os documentos correspondentes, mas você pode emitir uma consulta com $in e retornar todos os documentos correspondentes. Isso é melhor do que o operador de exclusão usado antes e agora podemos usar um índice para evitar varreduras de coleção completas.

Como abordagem final e para o melhor consideração de desempenho, você pode alterar o documento novamente para que no nível superior você mantenha o "status" de qualquer campo nos formulários em "void" ou "closed". Portanto, no nível superior, o valor seria fechado apenas se todos os itens fossem "fechados" e "void" se algo fosse nulo, e assim por diante.

Essa última significaria mais uma mudança programática, e todas as mudanças nos forms itens precisariam atualizar este campo também para manter o "status". No entanto, é a maneira mais eficiente de encontrar os documentos de que você precisa e pode valer a pena considerar.

EDITAR :

Além de alterar o documento para ter um status mestre, o formulário de consulta mais rápido na estrutura revisada é, na verdade:
db.forms.find({ "forms": { "$not": { "$elemMatch": { "status": "void" } } } })