Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Update em objeto da lista de um outro objeto

Saudações guerreiros!

Por favor, considerem o objeto "Tapioca" exibido abaixo:

{    
    "_id" : ObjectId("5bfff1027e1ad83f189ff76c"),
    "Preco" : "4.50",
    "Recheio" : [ 
        {
            "Nome" : "Carne Moída",
            "Quantidade" : "200g"
        }, 
        {
            "Nome" : "Queijo",
            "Quantidade" : "1"
        }, 
        {
            "Nome" : "Presunto",
            "Quantidade" : "1"
        }
    ]
}

Suponhamos que a partir de hoje, essa tapioca receberá um incremento. Agora ela será produzida com 2 fatias de queijo! Preciso atualizar somente a quantidade de queijo nessa tapioca.

        {
            "nome": "Quejo",
            "quantidade": "2"
        }
  • Agora na controller é que me apareceu a dúvida. Como faço pra atualizar somente a quantidade de queijo da minha tapioca?
  • Deveria eu, enviar no PUT o objeto Tapioca inteiro e sobrescrever o anterior do banco?
  • Qual a melhor alternativa e como fazer?

Segue abaixo o código da minha action, comecei a escrever o código da minha action, mas ainda não descobri como filtrar por tapioca e atualizar apenas a quantidade do queijo x)

    [HttpPut("{id}")]
    public async Task<IActionResult> Put(string id, [FromBody] Recheio model)
    {
            if (ModelState.IsValid)
            {                
                var filter = Builders<Tapioca>.Filter.Eq(a => a.Id, ObjectId.Parse(id));

                var update = Builders<Recheio>.Update.Set(a => a.Quantidade, model.Quantidade);

                await db.Tapiocas.UpdateOneAsync(filter, update);     

                return Accepted(model);
            }

            return BadRequest();
        }

Obrigado! =D

4 respostas
solução!

Oi Tiago, tudo bem?

Criei um projeto aqui para testar, e consegui com o seguinte código:

var filter = Builders<BsonDocument>.Filter.Eq("_id", id)
                & Builders<BsonDocument>.Filter.Eq("Recheio.Nome", model.Nome);
var update = Builders<BsonDocument>.Update.Set("Recheio.$.Quantidade", model.Quantidade);
await collection.UpdateOneAsync(filter, update);

Note que o filter precisa ser uma query complexa, pois você está:

  • pesquisando pelo Id da tapioca e
  • pesquisando pelo nome do recheio (model.Nome)

Além disso, a expressão dentro de Update.Set tem que ser uma string "Recheio.$.Quantidade", onde:

  • "Recheio" é o nome do campo do documento "Tapioca"
  • "$" indica que o campo "Recheio" anterior é um array e
  • "Quatidade" é a propriedade dentro do array "Recheio" que deve ser atualizada

Aeeee!! Vlww!! A única diferença foi que tive que fazer o parse do id:

Builders<BsonDocument>.Filter.Eq("_id", ObjectId.Parse(id))

Antes de encerrar o tópico, uma última dúvida:

  • Não conseguimos realizar o filtro utilizando o modelo fortemente tipado, tivemos que recorrer ao objeto raiz BsonDocument. Essa situação é comum quando se trabalha com bancos não relacionais, ou temos aqui um modelo mal desenhado?

Ah, no começo da sua aplicação você teria que registrar o mapeamento das classes envolvidas, por exemplo:

            BsonClassMap.RegisterClassMap<Tapioca>();
            BsonClassMap.RegisterClassMap<Recheio>();

E então mudar o tipo BsonDocument para Tapioca:

var filter = Builders<Tapioca>.Filter.Eq("_id", id)
                & Builders<Tapioca>.Filter.Eq("Recheio.Nome", model.Nome);
var update = Builders<Tapioca>.Update.Set("Recheio.$.Quantidade", model.Quantidade);
await collection.UpdateOneAsync(filter, update);

Muito obrigado! =D