Por que você não pode modificar os dados retornados por uma Consulta Mongoose (ex: findById)

94

Quando tento alterar qualquer parte dos dados retornados por uma Consulta do Mongoose, isso não tem efeito.

Eu estava tentando descobrir isso por cerca de 2 horas ontem, com todos os tipos de programas _.clone(), usando variáveis ​​de armazenamento temporário, etc. Finalmente, quando pensei que estava ficando louco, encontrei uma solução. Portanto, imaginei que alguém no futuro (fyuuuture!) Pode ter o problema de salvar.

Survey.findById(req.params.id, function(err, data){
    var len = data.survey_questions.length;
    var counter = 0;

    _.each(data.survey_questions, function(sq){
        Question.findById(sq.question, function(err, q){
            sq.question = q; //has no effect

            if(++counter == len) {
                res.send(data);
            }
        });
    });
});
Toli
fonte
possível duplicata de stackoverflow.com/q/9952649/4748042
martinho 31/01

Respostas:

160

Para casos como este, em que você deseja um objeto JS simples em vez de uma instância de modelo completa, você pode chamar lean()a cadeia de consulta assim:

Survey.findById(req.params.id).lean().exec(function(err, data){
    var len = data.survey_questions.length;
    var counter = 0;

    _.each(data.survey_questions, function(sq){
        Question.findById(sq.question, function(err, q){
            sq.question = q;

            if(++counter == len) {
                res.send(data);
            }
        });
    });
});

Dessa forma, datajá é um objeto JS simples que você pode manipular conforme necessário.

JohnnyHK
fonte
8
Btw @JohnnyHK só queria agradecer novamente. Um ano e meio depois, estava ajudando um cliente a depurar algo. Ele passou um fim de semana tentando descobrir algo, mas acabou descobrindo que era porque ele estava tentando modificar o Objeto Mongoose; P
Toli
1
2 anos depois e ainda esmagando. Nem percebi que lean () estava lá.
Petrogad
1
@Fizzix aggregatesempre fornece seus resultados como objetos simples, então não há necessidade de lean().
JohnnyHK
1
3 anos depois, passei uma hora inteira tentando descobrir. Salvei meu dia inteiro! Obrigado
Noy
2
Obrigado! Isso ajudou muito, mas por que é impossível modificar o objeto? Que tipo de objeto especial é?
Robert Fedus
46

Acho que a documentação do Mongoose não deixa isso claro o suficiente, mas os dados retornados na consulta (embora você possa res.send () isso) são, na verdade, um objeto de documento do Mongoose e NÃO um objeto JSON. Mas você pode consertar isso com uma linha ...

Survey.findById(req.params.id, function(err, data){
    var len = data.survey_questions.length;
    var counter = 0;

    var data = data.toJSON(); //turns it into JSON YAY!

    _.each(data.survey_questions, function(sq){
        Question.findById(sq.question, function(err, q){
            sq.question = q;

            if(++counter == len) {
                res.send(data);
            }
        });
    });
});
Toli
fonte
12
Você também pode usar toObject(), que faz a mesma coisa que, toJSON()mas com um nome menos confuso.
JohnnyHK
1
Isso também eliminará os virtuais colocados pelo desenvolvedor?
mjwrazor
5
TypeError: data.toObject is not a functionEu tenho isso, o mesmo comtoJSON
Luzan Baral
Em vez de modificar o result, fui capaz de modificar result._doc.
enésimo chile
@Luzan Baral Isso é porque você está usando essas funções para o objeto Array. Use em seu JSON.parse(JSON.stringify(data))lugar para Matrizes de objeto
mohit