Então você está correto em que o
$pull
O operador faz exatamente o que a documentação diz, pois seus argumentos são de fato uma "consulta" usada para corresponder aos elementos que devem ser removidos. Se o conteúdo do seu array sempre tiver o elemento na posição "primeira" conforme você mostra, o
$pop
de fato, o operador remove esse primeiro elemento. Com o driver de nó básico:
collection.findOneAndUpdate(
{ "array.0": "bird" }, // "array.0" is matching the value of the "first" element
{ "$pop": { "array": -1 } },
{ "returnOriginal": false },
function(err,doc) {
}
);
Com mangusto o argumento para retornar o documento modificado é diferente:
MyModel.findOneAndUpdate(
{ "array.0": "bird" },
{ "$pop": { "array": -1 } },
{ "new": true },
function(err,doc) {
}
);
Mas também não são de muita utilidade se a posição da matriz do "primeiro" item a ser removido não for conhecida.
Para a abordagem geral aqui, você precisa de "duas" atualizações, sendo uma para corresponder ao primeiro item e substituí-lo por algo exclusivo a ser removido e o segundo para remover esse item modificado.
Isso é muito mais simples se aplicar atualizações simples e não solicitar o documento retornado, e também pode ser feito em massa entre documentos. Também ajuda usar algo como async.series para evitar aninhar suas chamadas:
async.series(
[
function(callback) {
collection.update(
{ "array": "bird" },
{ "$unset": { "array.$": "" } },
{ "multi": true }
callback
);
},
function(callback) {
collection.update(
{ "array": null },
{ "$pull": { "array": null } },
{ "multi": true }
callback
);
}
],
function(err) {
// comes here when finished or on error
}
);
Então, usando o
$unset
aqui com o posicional $
operador permite que o "primeiro" item seja alterado para null
. Em seguida, a consulta subsequente com $pull
apenas remove qualquer null
entrada da matriz. É assim que você remove a "primeira" ocorrência de um valor com segurança de uma matriz. Para determinar se essa matriz contém mais de um valor que é o mesmo é outra questão.