SPL auxilia MongoDB a agrupar documentos adjacentes

Agrupar dados adjacentes pode ser um desafio em bancos de dados NoSQL como o MongoDB, especialmente quando se busca uma solução eficiente e direta. A flexibilidade do MongoDB, no entanto, permite que você explore alternativas para alcançar o resultado desejado, mesmo que isso envolva abordagens um pouco mais elaboradas do que as tradicionais. Vamos mostrar como lidar com essa tarefa de forma eficaz!

Agregação no MongoDB: Desafios e Soluções

No MongoDB, a agregação no MongoDB de estados adjacentes diretamente com consultas pode ser complexa, já que a linguagem de consulta nativa não oferece suporte direto a essa lógica de agrupamento. Para contornar essa limitação, é possível combinar o Aggregation Pipeline com alguma lógica customizada. Essa combinação permite implementar indiretamente a função de agrupar os estados vizinhos.

Imagine que você tem uma coleção de dados (chamada “estados”) em seu banco de dados MongoDB, organizada da seguinte forma:

[
  {order: 1, state: 'one'},
  {order: 2, state: 'one'},
  {order: 3, state: 'one'},
  {order: 4, state: 'two'},
  {order: 5, state: 'two'},
  {order: 6, state: 'one'},
  {order: 7, state: 'two'},
  {order: 8, state: 'three'},
  {order: 9, state: 'three'}
]

O objetivo é agrupar esses estados de forma adjacente, de modo que o resultado final seja:

[
  [
    {order: 1, state: 'one'},
    {order: 2, state: 'one'},
    {order: 3, state: 'one'}
  ],
  [
    {order: 4, state: 'two'},
    {order: 5, state: 'two'}
  ],
  [
    {order: 6, state: 'one'}
  ],
  [
    {order: 7, state: 'two'}
  ],
  [
    {order: 8, state: 'three'},
    {order: 9, state: 'three'}
  ]
]

Implementando a Agregação com Aggregation Pipeline

Para realizar essa tarefa, o Aggregation Pipeline oferece uma estrutura poderosa. Veja como você pode escrever o código para alcançar o resultado desejado:

db.states.aggregate([
  {
    $sort: { order: 1 }
  },
  {
    $group: {
      _id: null,
      documents: { $push: "$$ROOT" }
    }
  },
  {
    $project: {
      grouped: {
        $reduce: {
          input: "$documents",
          initialValue: {
            previousState: null,
            groups: []
          },
          in: {
            $let: {
              vars: {
                currentState: "$$this.state",
                lastGroup: { $arrayElemAt: ["$$value.groups", -1] }
              },
              in: {
                $cond: [
                  { $eq: ["$$value.previousState", "$$this.state"] },
                  {
                    previousState: "$$this.state",
                    groups: {
                      $concatArrays: [
                        { $slice: ["$$value.groups", { $subtract: [{ $size: "$$value.groups" }, 1] }] },
                        [
                          {
                            $concatArrays: [
                              "$$lastGroup",
                              ["$$this"]
                            ]
                          }
                        ]
                      ]
                    }
                  },
                  {
                    previousState: "$$this.state",
                    groups: {
                      $concatArrays: [
                        "$$value.groups",
                        [["$$this"]]
                      ]
                    }
                  }
                ]
              }
            }
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      grouped: "$grouped.groups"
    }
  },
  {
    $unwind: "$grouped"
  },
  {
    $project: {
      _id: 0,
      documents: "$grouped"
    }
  },
  {
    $group: {
      _id: null,
      result: { $push: "$documents" }
    }
  },
  {
    $project: {
      _id: 0,
      result: 1
    }
  }
])

Este código utiliza várias etapas do Aggregation Pipeline para ordenar os documentos, agrupar todos os documentos em um único array, e, em seguida, usar a função $reduce para iterar sobre os documentos e criar os grupos adjacentes com base no valor do estado. O resultado final é um array de arrays, onde cada sub-array contém os documentos agrupados por estados adjacentes.

Resultado da Execução

Ao executar o código acima, você obterá o seguinte resultado:

{
  result: [
    [
      {
        _id: ObjectId('67c65e846d497a00cd02a427'),
        order: 1,
        state: 'one'
      },
      {
        _id: ObjectId('67c65e846d497a00cd02a428'),
        order: 2,
        state: 'one'
      },
      {
        _id: ObjectId('67c65e846d497a00cd02a429'),
        order: 3,
        state: 'one'
      }
    ],
    [
      {
        _id: ObjectId('67c65e846d497a00cd02a42a'),
        order: 4,
        state: 'two'
      },
      {
        _id: ObjectId('67c65e846d497a00cd02a42b'),
        order: 5,
        state: 'two'
      }
    ],
    [
      {
        _id: ObjectId('67c65e846d497a00cd02a42c'),
        order: 6,
        state: 'one'
      }
    ],
    [
      {
        _id: ObjectId('67c65e846d497a00cd02a42d'),
        order: 7,
        state: 'two'
      }
    ],
    [
      {
        _id: ObjectId('67c65e846d497a00cd02a42e'),
        order: 8,
        state: 'three'
      },
      {
        _id: ObjectId('67c65e846d497a00cd02a42f'),
        order: 9,
        state: 'three'
      }
    ]
  ]
}

Este resultado mostra os documentos agrupados conforme o estado adjacente, atendendo ao requisito inicial.

Alternativa com SPL (Statistical Programming Language)

Uma alternativa para realizar essa tarefa é utilizar o SPL (Statistical Programming Language), que oferece uma função específica para agrupar registros adjacentes. O código em SPL é mais conciso e claro:

Image description

As três primeiras linhas são responsáveis pela leitura dos dados, e o cálculo é feito em uma única linha (A4). A linha A5 retorna os resultados em formato JSON, que são idênticos aos requisitos originais.

Em resumo, embora o MongoDB não ofereça uma solução direta para agrupar estados adjacentes com suas ferramentas nativas, é possível alcançar o resultado desejado combinando o Aggregation Pipeline com lógica customizada. Além disso, ferramentas como o SPL oferecem alternativas mais concisas e claras para essa tarefa.

Este conteúdo foi auxiliado por Inteligência Artificiado, mas escrito e revisado por um humano.

Leave a Comment