Eu tenho um documento Mongo que contém uma matriz de elementos.
Eu gostaria de redefinir o .handled
atributo de todos os objetos na matriz onde .profile
= XX.
O documento está no seguinte formato:
{
"_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
"events": [{
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 20,
"data": "....."
}
...
]
}
então, tentei o seguinte:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
No entanto, ele atualiza apenas o primeiro elemento da matriz correspondente em cada documento. (Esse é o comportamento definido para $ - o operador posicional .)
Como posso atualizar todos os elementos da matriz correspondentes?
arrays
mongodb
mongodb-query
LiorH
fonte
fonte
Respostas:
Nesse momento, não é possível usar o operador posicional para atualizar todos os itens em uma matriz. Veja JIRA http://jira.mongodb.org/browse/SERVER-1243
Como alternativa, você pode:
fonte
Com o lançamento do MongoDB 3.6 (e disponível no ramo de desenvolvimento do MongoDB 3.5.12), agora você pode atualizar vários elementos da matriz em uma única solicitação.
Isso usa a sintaxe do operador de atualização posicional filtrada
$[<identifier>]
apresentada nesta versão:O
"arrayFilters"
que passou para as opções para.update()
ou mesmo.updateOne()
,.updateMany()
,.findOneAndUpdate()
ou.bulkWrite()
método especifica as condições para combinar no identificador dada na instrução de atualização. Quaisquer elementos que correspondam à condição fornecida serão atualizados.Observando que o
"multi"
dado no contexto da pergunta foi usado na expectativa de que isso "atualizasse vários elementos", mas isso não foi e ainda não é o caso. Seu uso aqui se aplica a "vários documentos", como sempre foi o caso ou agora especificado de outra forma como a configuração obrigatória.updateMany()
nas versões modernas da API.Consulte também
positional all $[]
que também atualiza "vários elementos da matriz", mas sem aplicar às condições especificadas e se aplica a todos elementos da matriz em que essa é a ação desejada.Consulte também Atualizando uma matriz aninhada com o MongoDB para saber como esses novos operadores posicionais se aplicam a estruturas de matriz "aninhadas", onde "matrizes estão dentro de outras matrizes".
fonte
elem
?arrayFilters
, portanto, execute a atualização via CLI. stackoverflow.com/questions/48322834/…O que funcionou para mim foi o seguinte:
Eu acho que é mais claro para iniciantes no mongo e qualquer pessoa familiarizada com o JQuery e amigos.
fonte
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
e eu estou ficandoOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Quero executar essa atualização diretamente de um shell mongo sem usar a API Javascript.Isso também pode ser realizado com um loop while, que verifica se há algum documento que ainda tenha subdocumentos que não foram atualizados. Esse método preserva a atomicidade de suas atualizações (o que muitas das outras soluções aqui não).
O número de vezes que o loop é executado será igual ao número máximo de vezes que os subdocumentos são
profile
iguais a 10 ehandled
iguais a 0 em qualquer um dos documentos da sua coleção. Portanto, se você tiver 100 documentos em sua coleção e um deles tiver três subdocumentos correspondentesquery
e todos os outros documentos tiverem menos subdocumentos correspondentes, o loop será executado três vezes.Esse método evita o risco de sobrecarregar outros dados que podem ser atualizados por outro processo enquanto esse script é executado. Também minimiza a quantidade de dados sendo transferidos entre cliente e servidor.
fonte
De fato, isso se relaciona com a questão de longa data em http://jira.mongodb.org/browse/SERVER-1243, na qual existem de fato vários desafios a uma sintaxe clara que suporta "todos os casos" em que há várias correspondências de matriz. encontrado. De fato, já existem métodos que "ajudam" em soluções para esse problema, como Operações em Massa que foram implementadas após esta postagem original.
Ainda não é possível atualizar mais de um elemento de matriz combinada em uma única instrução de atualização, portanto, mesmo com uma atualização "multi", tudo o que você poderá atualizar é apenas um elemento matemático na matriz para cada documento naquele único declaração.
A melhor solução possível no momento é encontrar e fazer o loop de todos os documentos correspondentes e processar as atualizações em massa que permitirão pelo menos que muitas operações sejam enviadas em uma única solicitação com uma resposta única. Opcionalmente, você pode usar
.aggregate()
para reduzir o conteúdo da matriz retornado no resultado da pesquisa apenas para aqueles que correspondem às condições da seleção de atualização:A
.aggregate()
parte funcionará quando houver um identificador "exclusivo" para a matriz ou todo o conteúdo de cada elemento formar um elemento "exclusivo". Isso ocorre devido ao operador "set"$setDifference
usado para filtrar quaisquerfalse
valores retornados da$map
operação usada para processar a matriz para correspondências.Se o conteúdo da sua matriz não tiver elementos exclusivos, você pode tentar uma abordagem alternativa com
$redact
:Onde a limitação é que, se "manipulado" era de fato um campo destinado a estar presente em outros níveis de documento, é provável que você obtenha resultados inesperados, mas é bom que esse campo apareça apenas em uma posição de documento e corresponda à igualdade.
Versões futuras (MongoDB post 3.1) até o momento da gravação terão uma
$filter
operação mais simples:E todas as versões com suporte
.aggregate()
podem usar a seguinte abordagem$unwind
, mas o uso desse operador torna a abordagem menos eficiente devido à expansão da matriz no pipeline:Em todos os casos em que a versão do MongoDB suporta um "cursor" da saída agregada, é apenas uma questão de escolher uma abordagem e iterar os resultados com o mesmo bloco de código mostrado para processar as instruções de atualização em massa. Operações em massa e "cursores" da saída agregada são introduzidos na mesma versão (MongoDB 2.6) e, portanto, geralmente trabalham lado a lado no processamento.
Em versões ainda anteriores, provavelmente é melhor usar apenas
.find()
para retornar o cursor e filtrar a execução das instruções apenas o número de vezes que o elemento da matriz corresponde às.update()
iterações:Se você está determinado a fazer atualizações "múltiplas" ou considera-as mais eficientes do que processar várias atualizações para cada documento correspondente, sempre pode determinar o número máximo de correspondências possíveis de matriz e apenas executar uma atualização "múltipla" que muitos vezes, até que basicamente não haja mais documentos para atualizar.
Uma abordagem válida para as versões MongoDB 2.4 e 2.2 também pode ser usada
.aggregate()
para encontrar este valor:Seja qual for o caso, há certas coisas que você não deseja fazer na atualização:
Não "atualize" a matriz: onde, se você acha que seria mais eficiente atualizar todo o conteúdo da matriz no código e apenas
$set
a matriz inteira em cada documento. Isso pode parecer mais rápido de processar, mas não há garantia de que o conteúdo da matriz não tenha sido alterado desde que foi lido e a atualização foi realizada. Embora$set
ainda seja um operador atômico, ele somente atualizará a matriz com o que "pensa" como sendo os dados corretos e, portanto, provavelmente substituirá quaisquer alterações que ocorram entre leitura e gravação.Não calcule os valores do índice para atualizar: onde semelhante à abordagem "one shot", você apenas elabora que posição
0
e posição2
(e assim por diante) são os elementos para atualizar e codificá-los com uma declaração eventual como:Novamente, o problema aqui é a "presunção" de que esses valores de índice encontrados quando o documento foi lido são os mesmos valores de índice na matriz no momento da atualização. Se novos itens forem adicionados à matriz de uma maneira que altere a ordem, essas posições não serão mais válidas e os itens errados serão de fato atualizados.
Portanto, até que exista uma sintaxe razoável determinada para permitir que vários elementos da matriz correspondidos sejam processados na instrução de atualização única, a abordagem básica é atualizar cada elemento da matriz correspondida em uma declaração individual (idealmente em massa) ou essencialmente calcular os elementos máximos da matriz para atualizar ou continuar atualizando até que nenhum resultado modificado seja retornado. De qualquer forma, você deve "sempre" processar atualizações posicionais
$
no elemento de matriz correspondente, mesmo que isso esteja atualizando apenas um elemento por instrução.As operações em massa são, de fato, a solução "generalizada" para processar qualquer operação que funcione como "várias operações" e, como existem mais aplicativos para isso do que apenas atualizar elementos de matriz múltiplos com o mesmo valor, é claro que ela foi implementada já, e atualmente é a melhor abordagem para resolver esse problema.
fonte
Estou surpreso que isso ainda não tenha sido tratado no mongo. No geral, o mongo não parece ser ótimo quando se lida com sub-matrizes. Você não pode contar sub-matrizes simplesmente por exemplo.
Eu usei a primeira solução de Javier. Leia a matriz em eventos, faça um loop e construa o conjunto exp:
Isso pode ser abstraído em uma função usando um retorno de chamada para o teste condicional
fonte
Eu estava procurando uma solução para isso usando o driver mais recente para o C # 3.6 e aqui está a correção em que eu finalmente resolvi. A chave aqui é usar "$ []" que, de acordo com o MongoDB, é novo na versão 3.6. Consulte https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] para mais informações.
Aqui está o código:
Para obter mais contexto, consulte meu post original aqui: Remova o elemento da matriz de TODOS os documentos usando o driver MongoDB C #
fonte
O tópico é muito antigo, mas eu vim procurando respostas aqui, portanto, fornecendo uma nova solução.
Com o MongoDB versão 3.6+, agora é possível usar o operador posicional para atualizar todos os itens em uma matriz. Veja a documentação oficial aqui .
A consulta a seguir funcionaria para a pergunta feita aqui. Também verifiquei com o driver Java-MongoDB e funciona com sucesso.
Espero que isso ajude alguém como eu.
fonte
Eu tentei o seguinte e está funcionando bem.
// função de retorno de chamada no caso de nodejs
fonte
Você pode atualizar todos os elementos no MongoDB
Ele atualizará todo o valor "status" para "complete" na matriz "arr"
Se apenas um documento
Mas se não for um, e você também não quiser que todos os documentos da matriz sejam atualizados, precisará percorrer o elemento e o bloco if
fonte
Na verdade, o comando save é apenas na instância da classe Document. Que possuem muitos métodos e atributos. Portanto, você pode usar a função lean () para reduzir a carga de trabalho. Consulte aqui. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Outro problema com a função de salvar, que cria dados de conflito com o salvamento múltiplo ao mesmo tempo. Model.Update fará com que os dados sejam consistentes. Então, para atualizar vários itens na matriz do documento. Use sua linguagem de programação familiar e tente algo parecido com isto, eu uso o mangusto nisso:
fonte
O operador $ [] seleciona toda a matriz aninhada. Você pode atualizar todos os itens da matriz com '$ []'
Referência
fonte
$[]
apenas atualiza todos os campos na matriz especificada. O que funciona é o operador posicional filtrado que opera$[identifier]
nos campos da matriz que correspondem às condições especificadas. Deve ser usado com oarrayFilters
Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters e docs.mongodb.com/manual/reference/operator/update/Esteja ciente de que algumas respostas neste tópico sugerindo o uso de $ [] estão ERRADAS.
O código acima atualizará "manipulado" para 0 para todos os elementos na matriz "events", independentemente de seu valor "profile". A consulta
{"events.profile":10}
é apenas para filtrar o documento inteiro, não os documentos da matriz. Nessa situação, é necessário usar$[elem]
comarrayFilters
para especificar a condição dos itens da matriz, para que a resposta de Neil Lunn esteja correta.fonte
Atualize o campo da matriz em vários documentos no mongo db.
Use $ pull ou $ push com a atualização de muitas consultas para atualizar os elementos da matriz no mongoDb.
fonte
Primeiro: seu código não funcionou porque você estava usando o operador posicional
$
que identifica apenas um elemento a ser atualizado em uma matriz, mas nem especifica explicitamente sua posição na matriz.O que você precisa é do operador posicional filtrado
$[<identifier>]
. Ele atualiza todos os elementos que correspondem a uma condição de filtro de matriz.Solução:
Visite mongodb doc aqui
O que o código faz:
{"events.profile":10}
filtra sua coleção e retorna os documentos correspondentes ao filtroO
$set
operador de atualização: modifica os campos correspondentes dos documentos em que atua.{multi:true}
Faz.update()
modifica todos os documentos correspondentes ao filtro, portanto, se comportando comoupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Essa técnica envolve o uso da matriz posicional filtrada com arrayFilters. a matriz posicional filtrada aqui$[elem]
atua como um espaço reservado para todos os elementos nos campos da matriz que correspondem às condições especificadas no filtro da matriz.Filtros de matriz
fonte