No MongoDB, um índice exclusivo garante que um determinado valor em um campo não esteja presente em mais de um documento. Ele não garantem que um valor seja exclusivo em uma matriz em um único documento. Isso é explicado aqui no Manual do MongoDB, onde discute índices multichave exclusivos.
Assim, um índice exclusivo não satisfará sua necessidade. Isso impedirá que documentos separados contenham combinações duplicadas, mas ainda permitirá que um único documento contenha valores duplicados em uma matriz.
A melhor opção que você tem é alterar seu modelo de dados para dividir a matriz de objetos technologyEmployeeRef em documentos separados. Dividi-lo em documentos separados permitirá que você use um índice exclusivo para impor a exclusividade.
A implementação específica que deve ser feita para essa alteração do modelo de dados dependeria do seu padrão de acesso (que está fora do escopo desta questão).
Uma maneira de fazer isso é criar uma coleção TechnologyEmployee que tenha todos os campos que existem atualmente no array technologyEmployeeRef. Além disso, essa coleção TechnologyEmployee teria um campo, como email, que permitiria associá-la a um documento na coleção Employee.
Exemplo de documento do funcionário
{
....
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
.....
.....
}
Amostra de Documento de Tecnologia do Funcionário
{
"email" : "[email protected]",
"technologyCd" : "Java",
"technologyName" : "Java8",
....
.....
"status" : "A"
}
Índice na coleção EmployeeTechnology
{'email' : 1, 'technologyCd' : 1}, {unique: true}
A desvantagem dessa abordagem é que você precisaria ler duas coleções para ter todos os dados. Essa desvantagem pode não ser um grande problema se você raramente precisar recuperar os dados de ambas as coleções ao mesmo tempo. Se você precisar de todos os dados, eles podem ser acelerados por meio do uso de índices. Com os índices, pôde-se agilizar ainda mais com o uso de consultas cobertas.
Outra opção é desnormalizar os dados. Você faria isso duplicando os dados do Funcionário que você precisa acessar ao mesmo tempo que os dados da Tecnologia.
Documentos de amostra
[
{
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
"technologyCd" : "Java",
"technologyName" : "Java8",
....
"status" : "A"
},
{
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
"technologyCd" : "Spring",
"technologyName" : "Spring Boot2",
....
"status" : "A"
}
]
Neste post do blog do MongoDB, eles dizem que
Você faria isso apenas para campos que são lidos com frequência, lidos com muito mais frequência do que atualizados e onde você não exige consistência forte, pois atualizar um valor desnormalizado é mais lento, mais caro e não é atômico.
Ou, como você já mencionou, pode fazer sentido deixar o modelo de dados como está e realizar a verificação de exclusividade no lado do aplicativo. Isso provavelmente pode fornecer o melhor desempenho de leitura, mas vem com algumas desvantagens. Primeiro, ele desacelerará as operações de gravação porque o aplicativo precisará executar algumas verificações antes de poder atualizar o banco de dados.
Pode ser improvável, mas também existe a possibilidade de você ainda acabar com duplicatas. Se houver duas solicitações consecutivas para inserir o mesmo objeto EmployeeTechnology na matriz, a validação da segunda solicitação poderá ser concluída (e aprovada) antes que a primeira solicitação seja gravada no banco de dados. Eu mesmo vi um cenário semelhante com um aplicativo em que trabalhei. Mesmo que o aplicativo estivesse verificando a exclusividade, se um usuário clicasse duas vezes em um botão de envio, haveria entradas duplicadas no banco de dados. Nesse caso, desabilitar o botão no primeiro clique reduziu drasticamente o risco. Esse pequeno risco pode ser tolerável, dependendo de seus requisitos e do impacto de ter entradas duplicadas.
Qual abordagem faz mais sentido depende em grande parte do seu padrão de acesso e requisitos. Espero que isto ajude.