Se eu essencialmente entendo sua essência, você basicamente quer
- Puxe o item que não é necessário de sua matriz de referências
- Defina o valor do seu campo de referência principal para o primeiro elemento da matriz alterada
E faça tudo isso em uma atualização sem mover documentos pela rede.
Mas isso infelizmente não pode ser feito. O principal problema com isso é que não há como fazer referência ao valor de outro campo dentro do documento que está sendo atualizado. Mesmo assim, para fazer isso sem iterar, você também precisaria acessar o alterado array para obter o novo primeiro elemento.
Talvez uma abordagem seja repensar seu esquema para realizar o que você deseja. Minha opção aqui seria expandir um pouco seus documentos de referência e remover a necessidade do campo de referência principal.
Parece que a suposição com a qual você está disposto a conviver com as atualizações é que, se a referência removida era a referência principal, você pode simplesmente definir a nova referência principal para o primeiro elemento da matriz. Com isso em mente, considere a seguinte estrutura:
refs: [ { oid: "object1" }, { oid: "object2" }, { oid: "object5", main: true } ]
Ao alterá-los para documentos com um
oid
propriedade que seria definida para o ObjectId dá a opção de ter uma propriedade adicional no documento que especifica qual é o padrão. Isso pode ser facilmente consultado para determinar qual Id é a referência principal. Agora considere também o que aconteceria se o documento correspondente a "object5" no campo oid fosse extraído do array:
refs: [ { oid: "object1" }, { oid: "object2" } ]
Então, quando você consulta qual é a
main-reference
de acordo com a lógica anterior, você aceita o primeiro documento na matriz. Agora, é claro, para os requisitos do seu aplicativo, se você quiser definir uma main-reference
diferente você acabou de alterar o documento refs: [ { oid: "object1" }, { oid: "object2", main: true } ]
E agora a lógica permanece para escolher o elemento da matriz que tem a propriedade main como true ocorreria de preferência, e como mostrado acima, se essa propriedade não existir em nenhum documento de elementos, volte para o primeiro elemento.
Com tudo isso digerido, sua operação para extrair todas as referências a um objeto desse array em todos os documentos se torna bastante simples, como feito no shell (o mesmo formato deve se aplicar basicamente a qualquer driver):
db.books.update(
{ "refs.oid": "object5" },
{ $pull: { refs: {oid: "object5"} } }, false, true )
Os dois argumentos extras para a operação de consulta e atualização sendo
upsert
e multi
respectivamente. Neste caso, upsert
não faz muito sentido, pois queremos apenas modificar os documentos que existem, e multi
significa que queremos atualizar tudo o que corresponde. O padrão é alterar apenas o primeiro documento. Naturalmente eu encurtei toda a notação, mas é claro que os valores podem ser ObjectIds reais conforme sua intenção. Também parecia razoável presumir que seu uso principal do
main-reference
é uma vez que você recuperou o documento. Definindo uma consulta que retorna a main-reference
seguindo a lógica que foi delineada deve ser possível, mas do jeito que está eu digitei muito aqui e preciso fazer uma pausa para o jantar :) Acho que isso apresenta um caso que vale a pena repensar seu esquema para evitar iterações diretas para o que você deseja alcançar.