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

Como posso $ addToSet um objeto para um array e $ sort também usando o MongoDB?


Você fez parte do caminho até lá ao identificar corretamente as operações que precisa fazer. Mas é claro $sort não é um modificador válido para $addToSet já que o mantra do MongoDB é "conjuntos não são considerados ordenados" :

O outro problema aqui indicado pelo erro é que você não pode usar vários operadores de atualização (como $addToSet e $push ) no mesmo caminho para uma propriedade ao mesmo tempo. Na verdade, não há "ordem" na execução de diferentes operadores de atualização, portanto, não há garantia de que o $addToSet ocorre antes do $push . Na verdade eles provavelmente estão agindo em paralelo, razão pela qual o erro e que isso não é permitido.

A resposta, claro, é "duas" instruções de atualização. Um para o $addToSet e um para aplicar o $sort "enviando" uma matriz vazia por meio de $each ,

Mas como realmente não queremos "esperar" a conclusão de cada atualização, é para isso que serve a API de operações "em massa". Assim, você pode enviar as duas instruções para o servidor em um envie e receba um resposta:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ "name": "Risas" }).update({ 
   "$addToSet": { 
       "propiedades": { "name": "cola", "cantidad": 1 }
   }
});
bulk.find({ "name": "Risas" }).update({ 
   "$push": { 
       "propiedades": { 
           "$each": [ ], "$sort": { "cantidad": -1 } 
        }
   }
});
bulk.execute();

Portanto, isso ainda é apenas uma solicitação ao servidor e uma resposta. Ainda são "duas" operações, mas a sobrecarga e a possibilidade de algum segmento agarrar o estado provisório do upadte são insignificantes.

Existe uma alternativa para esta abordagem que é mover a lógica "definir detecção" para o .find() parte da instrução de atualização e, em seguida, basta aplicar $push onde os membros a serem adicionados ao "conjunto" ainda não existem:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ 
    "name": "Risas", 
    "propiedades": { 
        "$not": { "$elemMatch": { "name": "cola", "cantidad": 1 } } 
    } 
}).update({ 
   "$push": { 
       "propiedades": { 
           "$each": [{ "name": "cola", "cantidad": 1 }], "$sort": { "cantidad": -1 } 
        }
   }
});
bulk.execute();

É claro que a complicação é que, se você estiver adicionando "vários" elementos de matriz aqui, precisará agrupar esses $not e $elemMacth testes em um $and condição e, então, se "apenas um" desses elementos fosse válido, ele não poderia ser adicionado sozinho.

Você pode "tentar" esse tipo de operação com "vários" itens "primeiro", mas então deveria ter uma execução "fallback" de cada elemento de array individual com a mesma lógica acima para "testar" a possibilidade de "empurrar" para cada um.

Então $addToSet torna essa segunda parte fácil com várias entradas de matriz. Para uma entrada é bastante simples apenas "consultar" e $push , para mais de um é provavelmente o caminho mais curto para usar o "primeiro" padrão com $addToSet e $push uma matriz vazia para "classificar" o resultado, pois aplicar o segundo padrão significa vários testes de atualização de qualquer maneira.