Talvez seja a hora, talvez seja eu me afogando em documentação esparsa e não sendo capaz de entender o conceito de atualização no Mongoose :)
Aqui está o acordo:
Eu tenho um esquema e um modelo de contato (propriedades reduzidas):
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var mongooseTypes = require("mongoose-types"),
useTimestamps = mongooseTypes.useTimestamps;
var ContactSchema = new Schema({
phone: {
type: String,
index: {
unique: true,
dropDups: true
}
},
status: {
type: String,
lowercase: true,
trim: true,
default: 'on'
}
});
ContactSchema.plugin(useTimestamps);
var Contact = mongoose.model('Contact', ContactSchema);
Recebo uma solicitação do cliente, contendo os campos necessários e uso meu modelo da seguinte maneira:
mongoose.connect(connectionString);
var contact = new Contact({
phone: request.phone,
status: request.status
});
E agora chegamos ao problema:
- Se eu ligar
contact.save(function(err){...})
, receberei um erro se o contato com o mesmo número de telefone já existir (conforme o esperado - único) - Não consigo ligar
update()
para contato, pois esse método não existe em um documento - Se eu chamar atualização no modelo:
Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
eu entro em um loop infinito de alguns tipos, já que a implementação da atualização do Mongoose claramente não quer um objeto como o segundo parâmetro. - Se eu fizer o mesmo, mas no segundo parâmetro eu passar uma matriz associativa das propriedades do pedido
{status: request.status, phone: request.phone ...}
funciona - mas então eu não tenho nenhuma referência ao contacto específico e não pode descobrir suascreatedAt
eupdatedAt
propriedades.
Então, a questão de fundo, depois de tudo o que tentei: dado um documento contact
, como atualizá-lo, se ele existir, ou adicioná-lo, se não existir?
Obrigado pelo seu tempo.
javascript
mongodb
node.js
mongoose
Travelling Tech Guy
fonte
fonte
pre
parasave
?Respostas:
O Mongoose agora suporta isso nativamente com o findOneAndUpdate (chama o MongoDB findAndModify ).
A opção upsert = true cria o objeto se ele não existir. o padrão é false .
Nas versões anteriores, o Mongoose não suporta esses ganchos com este método:
fonte
Eu apenas queimei umas 3 horas sólidas tentando resolver o mesmo problema. Especificamente, eu queria "substituir" o documento inteiro, se existir, ou inseri-lo de outra forma. Aqui está a solução:
Criei um problema na página do projeto Mongoose solicitando que informações sobre isso fossem adicionadas aos documentos.
fonte
MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
eMyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, fn);
Você estava perto de
mas seu segundo parâmetro deve ser um objeto com um operador de modificação, por exemplo
fonte
{$set: ... }
parte aqui como sua forma automática minha leituraBem, eu esperei o tempo suficiente e sem resposta. Finalmente desistiu de toda a abordagem de atualização / upsert e acompanhou:
Funciona? Sim. Estou feliz com isso? Provavelmente não. 2 chamadas de banco de dados em vez de uma.
Esperamos que uma futura implementação do Mongoose venha com uma
Model.upsert
função.fonte
runValidators: true
durante uma atualização: atualização docs (no entanto, atualização validadores só correr em$set
e$unset
operações).upsert()
estar disponível em todos os modelos. stackoverflow.com/a/50208331/1586406Solução muito elegante que você pode conseguir usando a cadeia de promessas:
fonte
(model) => { return model.save(); }
comomodel => model.save()
, e também(err) => { res.send(err); }
comoerr => res.send(err)
;)Eu sou o mantenedor do Mongoose. A maneira mais moderna para Upsert um doc é usar a
Model.updateOne()
função .Se você precisar do documento com upsert, poderá usar
Model.findOneAndUpdate()
A principal dica é que você precisa colocar as propriedades exclusivas no
filter
parâmetro paraupdateOne()
oufindOneAndUpdate()
, e as outras propriedades noupdate
parâmetro.Aqui está um tutorial sobre como aumentar documentos com o Mongoose .
fonte
Eu criei uma conta StackOverflow APENAS para responder a esta pergunta. Depois de procurar infrutuosamente as interwebs, acabei de escrever algo. Foi assim que fiz, para que possa ser aplicado a qualquer modelo de mangusto. Importe essa função ou adicione-a diretamente ao seu código onde você está fazendo a atualização.
Em seguida, para converter um documento em mangusto, faça o seguinte,
Esta solução pode exigir 2 chamadas de banco de dados, mas você obtém o benefício de,
Lembre-se de que o objeto de destino sempre substituirá a fonte, mesmo se a fonte tiver um valor existente
Além disso, para matrizes, se o objeto existente tiver uma matriz mais longa que a que está sendo substituída, os valores no final da matriz antiga permanecerão. Uma maneira fácil de alterar a matriz inteira é definir a matriz antiga como uma matriz vazia antes da upsert, se é isso que você pretende fazer.
ATUALIZAÇÃO - 16/01/2016 Adicionei uma condição extra para que, se houver uma matriz de valores primitivos, o Mongoose não perceba que a matriz é atualizada sem usar a função "set".
fonte
if(_.isObject(value) && _.keys(value).length !== 0) {
a condição de guarda para parar o estouro da pilha. Lodash 4+ aqui, parece converter valores não-objetos em objetos nakeys
chamada, portanto a proteção recursiva sempre foi verdadeira. Talvez haja uma maneira melhor, mas a sua quase trabalhando para mim agora ...Eu precisava atualizar / upsert um documento em uma coleção, o que fiz foi criar um novo objeto literal como este:
composto de dados que eu recebo de outro lugar no meu banco de dados e depois chamo de atualização no Model
esta é a saída que eu recebo depois de executar o script pela primeira vez:
E esta é a saída quando executo o script pela segunda vez:
Estou usando o mangusto versão 3.6.16
fonte
Aqui está uma abordagem melhor para resolver o método de atualização no mangusto, você pode verificar o Scotch.io para obter mais detalhes. Definitivamente funcionou para mim !!!
fonte
Existe um bug introduzido na 2.6 e afeta também a 2.7
O upsert costumava funcionar corretamente no 2.4
https://groups.google.com/forum/#!topic/mongodb-user/UcKvx4p4hnY https://jira.mongodb.org/browse/SERVER-13843
Dê uma olhada, ele contém algumas informações importantes
ATUALIZADA:
Isso não significa que upsert não funciona. Aqui está um bom exemplo de como usá-lo:
fonte
Você pode simplesmente atualizar o registro com isso e obter os dados atualizados em resposta
fonte
isso funcionou para mim.
fonte
Aqui está a maneira mais simples de criar / atualizar enquanto também chama o middleware e os validadores.
fonte
Para quem chega aqui ainda está procurando uma solução boa para "upserting" com suporte a ganchos, é isso que testei e trabalho. Ele ainda requer 2 chamadas de banco de dados, mas é muito mais estável do que qualquer coisa que eu tentei em uma única chamada.
fonte
Se houver geradores disponíveis, fica ainda mais fácil:
fonte
Nenhuma outra solução funcionou para mim. Estou usando uma solicitação de postagem e atualizando os dados, se encontrado, insira-os, também _id é enviado com o corpo da solicitação que precisa ser removido.
fonte
fonte
fonte
Seguindo a resposta do Traveling Tech Guy , que já é incrível, podemos criar um plug-in e anexá-lo ao mangusto assim que o inicializarmos, para que
.upsert()
fique disponível em todos os modelos.plugins.js
db.js
Então você pode fazer algo como
User.upsert({ _id: 1 }, { foo: 'bar' })
ouYouModel.upsert({ bar: 'foo' }, { value: 1 })
quando quiser.fonte
Acabei de voltar para esse problema depois de um tempo e decidi publicar um plug-in com base na resposta de Aaron Mast.
https://www.npmjs.com/package/mongoose-recursive-upsert
Use-o como um plugin mangusto. Ele configura um método estático que mesclará recursivamente o objeto passado.
fonte
Esse coffeescript funciona para mim com o Node - o truque é que os _id são removidos do seu wrapper ObjectID quando enviados e retornados do cliente e, portanto, precisam ser substituídos por atualizações (quando nenhum _id for fornecido, save será revertido para inserir e adicionar 1).
fonte
para construir sobre o que Martin Kuzdowicz postou acima. Eu uso o seguinte para fazer uma atualização usando mangusto e uma mesclagem profunda de objetos json. Juntamente com a função model.save () no mangusto, isso permite que o mangusto faça uma validação completa, mesmo que confie em outros valores no json. requer o pacote deepmerge https://www.npmjs.com/package/deepmerge . Mas esse é um pacote muito leve.
fonte
req.body
como está antes de testar a injeção de NoSQL (consulte owasp.org/index.php/Testing_for_NoSQL_injection ).Depois de ler as postagens acima, decidi usar este código:
se r for nulo, criamos um novo item. Caso contrário, use upsert na atualização porque a atualização não cria um novo item.
fonte