Como eliminar um banco de dados com o Mongoose?

97

Estou preparando um script de criação de banco de dados em Node.js e Mongoose. Como posso verificar se o banco de dados já existe e, em caso afirmativo, descartá-lo (excluí-lo) usando o Mongoose?

Não consegui encontrar uma maneira de largá-lo com o Mongoose.

Yaron Naveh
fonte
Duplicado: stackoverflow.com/questions/11453617/…
Uday Hiwarale

Respostas:

166

Não existe um método para retirar uma coleção do mangusto, o melhor que você pode fazer é remover o conteúdo de uma:

Model.remove({}, function(err) { 
   console.log('collection removed') 
});

Mas há uma maneira de acessar o driver javascript nativo mongodb, que pode ser usado para isso

mongoose.connection.collections['collectionName'].drop( function(err) {
    console.log('collection dropped');
});

Aviso

Faça um backup antes de tentar, caso algo dê errado!

Drinchev
fonte
2
quando tento a segunda opção, obtenho "não é possível ler a propriedade 'collectionName' de undefined"
Yaron Naveh
1
Como todas as coleções estão no hash mongoose.connection.collections, você pode simplesmente listá-las para (coleção em mongoose.connection.collections) {mongoose.connection.collections [coleção] .drop} ... smth similar
drinchev
3
Ocorreu um erro de digitação - uma vírgula extra após a função (err) ... deveria ser: mongoose.connection.collections ['collectionName']. Drop (function (err) {console.log ('collection drop') ;});
arxpoetica
3
Eu sou o único que percebeu que esta resposta não aborda a questão de como descartar um banco de dados. Não é pedir para descartar uma coleção, é pedir para descartar um banco de dados.
Joseph Persie
3
"Não existe um método para retirar uma coleção de mongoose", em primeiro lugar o OP deseja excluir um banco de dados, não um agrupamento, segundo a resposta de @hellslam abaixo funciona bem.
SCBuergel.eth
79

O Mongoose criará um banco de dados, se ainda não houver um na conexão, portanto, depois de fazer a conexão, você pode apenas consultá-lo para ver se há algo nele.

Você pode descartar qualquer banco de dados ao qual esteja conectado:

var mongoose = require('mongoose');
/* Connect to the DB */
mongoose.connect('mongodb://localhost/mydatabase',function(){
    /* Drop the DB */
    mongoose.connection.db.dropDatabase();
});
Hellslam
fonte
1
Eu tentei mongoose.connection.db.dropDatabase()mas descobri que o db ainda está lá? Eu sinto falta de alguma coisa?
Freewind de
Se você se conectasse a ele posteriormente, ele seria recriado, embora vazio. Houve alguma coleção depois que você o largou?
Hellslam de
Você está usando a mesma conexão ou criando várias conexões?
Hellslam de
12
Achei que a dropDatabaseinvocação deveria ser colocada no retorno de chamada de connect, as mongoose.connect('...', function() { ...dropDatabase()}).
Freewind de
1
dropDatabase parece não funcionar em alguns casos, mas o comando mongo direto ainda pode ser usado mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function(err, result) { if (err) { console.log(err); } done(); });
farincz
14

Se você modificar a solução de @hellslam assim, ela funcionará

Eu uso esta técnica para descartar o banco de dados após meus testes de integração

//CoffeeScript
mongoose = require "mongoose"
conn = mongoose.connect("mongodb://localhost/mydb")

conn.connection.db.dropDatabase()

//JavaScript
var conn, mongoose;
mongoose = require("mongoose");
conn = mongoose.connect("mongodb://localhost/mydb");

conn.connection.db.dropDatabase();

HTH pelo menos funcionou para mim, então decidi compartilhar =)

silverfighter
fonte
é possível derrubar db com isso? db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);
chovy de
2
Isso foi útil, obrigado! No entanto, seus nomes de variáveis ​​são um pouco enganadores ... mongoose.connectrealmente retorna mongoose. Em vez de conn = mongoose.connect(...)escrever mongoose.connect(...)e então conn = mongooose.connection.
um nerd pago de
Não acho que esse código sempre funcionará porque o connecté assíncrono. Portanto, se a conexão não acontecer imediatamente, o comando dropDatabase () falhará. É por isso que as outras soluções acima recomendaram colocar o dropDatabasecomando no retorno de chamada para a connectinstrução ou um openmanipulador de eventos.
Mark Stosberg
8

Tentei as respostas de @hellslam e @ silverfighter. Encontrei uma condição de corrida impedindo meus testes. No meu caso estou executando testes mocha e na função before do teste quero apagar todo o banco de dados. Aqui está o que funciona para mim.

var con = mongoose.connect('mongodb://localhost/mydatabase');
mongoose.connection.on('open', function(){
    con.connection.db.dropDatabase(function(err, result){
        done();
    });
});

Você pode ler mais https://github.com/Automattic/mongoose/issues/1469

Zafrani
fonte
7

Uma resposta atualizada, para 4.6.0+, se você tiver uma preferência por promessas ( consulte os documentos ):

mongoose.connect('mongodb://localhost/mydb', { useMongoClient: true })
.then((connection) => {
   connection.db.dropDatabase();
   // alternatively:
   // mongoose.connection.db.dropDatabase();
});

Testei esse código em meu próprio código, usando o mongoose 4.13.6. Além disso, observe o uso da useMongoClientopção ( consulte os documentos ). Documentos indicam:

A lógica de conexão padrão do Mongoose está obsoleta a partir de 4.11.0. Aceite a nova lógica de conexão usando a opção useMongoClient, mas certifique-se de testar suas conexões primeiro se estiver atualizando uma base de código existente!

Andre M
fonte
5

A dificuldade que tive com as outras soluções é que elas precisam reiniciar o aplicativo se você quiser que os índices funcionem novamente.

Para minhas necessidades (ou seja, ser capaz de executar um teste de unidade nos nukes de todas as coleções e, em seguida, recriá-los junto com seus índices), acabei implementando esta solução:

Isso se baseia nas bibliotecas underscore.js e async.js para montar os índices em paralelo, ele poderia ser desfeito se você for contra essa biblioteca, mas deixo isso como um exercício para o desenvolvedor.

mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function(err, result) {
  var mongoPath = mongoose.connections[0].host + ':' + mongoose.connections[0].port + '/' + mongoose.connections[0].name
  //Kill the current connection, then re-establish it
  mongoose.connection.close()
  mongoose.connect('mongodb://' + mongoPath, function(err){
    var asyncFunctions = []

    //Loop through all the known schemas, and execute an ensureIndex to make sure we're clean
    _.each(mongoose.connections[0].base.modelSchemas, function(schema, key) {
      asyncFunctions.push(function(cb){
        mongoose.model(key, schema).ensureIndexes(function(){
          return cb()
        })
      })
    })

    async.parallel(asyncFunctions, function(err) {
      console.log('Done dumping all collections and recreating indexes')
    })
  })
})
Eric Caron
fonte
4

Para esvaziar uma coleção específica em um banco de dados:

model.remove(function(err, p){
    if(err){ 
        throw err;
    } else{
        console.log('No Of Documents deleted:' + p);
    }
});

Nota:

  1. Escolha um modelo que se refira a um esquema específico (esquema de coleção que você deseja excluir).
  2. Esta operação não excluirá o nome da coleção do banco de dados.
  3. Isso exclui todos os documentos de uma coleção.
dinamarquês
fonte
4

Isso funciona para mim a partir do Mongoose v4.7.0:

mongoose.connection.dropDatabase();
user3344977
fonte
4

A melhor maneira de eliminar seu banco de dados no Mongoose depende de qual versão do Mongoose você está usando. Se você estiver usando uma versão do Mongoose 4.6.4 ou mais recente, este método adicionado nessa versão provavelmente funcionará bem para você:

mongoose.connection.dropDatabase();

Em versões mais antigas, esse método não existia. Em vez disso, você deveria usar uma chamada direta do MongoDB:

mongoose.connection.db.dropDatabase();

No entanto, se for executado logo após a criação da conexão com o banco de dados, pode ocorrer uma falha silenciosa. Isso está relacionado ao fato de a conexão ser realmente assíncrona e não ter sido configurada ainda quando o comando ocorrer. Normalmente, isso não é um problema para outras chamadas do Mongoose, como .find(), que ficam na fila até que a conexão seja aberta e depois executada.

Se você olhar o código-fonte do dropDatabase()atalho que foi adicionado, verá que ele foi projetado para resolver exatamente esse problema. Ele verifica se a conexão está aberta e pronta. Nesse caso, ele dispara o comando imediatamente. Caso contrário, ele registra o comando a ser executado quando a conexão com o banco de dados for aberta.

Algumas das sugestões acima recomendam sempre colocar seu dropDatabasecomando no openmanipulador. Mas isso só funciona no caso em que a conexão ainda não está aberta.

Connection.prototype.dropDatabase = function(callback) {
  var Promise = PromiseProvider.get();
  var _this = this;
  var promise = new Promise.ES6(function(resolve, reject) {
    if (_this.readyState !== STATES.connected) {
      _this.on('open', function() {
        _this.db.dropDatabase(function(error) {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        });
      });
    } else {
      _this.db.dropDatabase(function(error) {
        if (error) {
          reject(error);
        } else {
          resolve();
        }
      });
    }
  });
  if (callback) {
    promise.then(function() { callback(); }, callback);
  }
  return promise;
};

Esta é uma versão simples da lógica acima que pode ser usada com versões anteriores do Mongoose:

// This shim is backported from Mongoose 4.6.4 to reliably drop a database
// http://stackoverflow.com/a/42860208/254318
// The first arg should be "mongoose.connection"
function dropDatabase (connection, callback) {
    // readyState 1 === 'connected'
    if (connection.readyState !== 1) {
      connection.on('open', function() {
        connection.db.dropDatabase(callback);
      });
    } else {
      connection.db.dropDatabase(callback);
    }
}  
Mark Stosberg
fonte
2

Mongoose 4.6.0+:

mongoose.connect('mongodb://localhost/mydb')
mongoose.connection.once('connected', () => {
    mongoose.connection.db.dropDatabase();
});

Passar uma chamada de retorno para se conectar não funcionará mais:

TypeError: Não é possível ler a propriedade 'commandsTakeWriteConcern' de null

Rayjax
fonte
1
connectretorna uma promessa, para que você possa adicioná .then((connection) => { ... });-la ao mongoose.connect. Consulte: mongoosejs.com/docs/connections.html
Andre M
1
beforeEach((done) => {
      mongoose.connection.dropCollection('products',(error ,result) => {
      if (error) {
        console.log('Products Collection is not dropped')
      } else {
        console.log(result)
      }
    done()
    })
  })
Revt A
fonte
0

Como o método remove é depreciado na biblioteca mongoose, podemos usar a função deleteMany sem parâmetros passados.

Model.deleteMany();

Isso excluirá todo o conteúdo deste modelo específico e sua coleção ficará vazia.

SAYAM.S SANGHVI
fonte
0

Para soltar todos os documentos em uma coleção:

await mongoose.connection.db.dropDatabase();

Esta resposta é baseada no arquivo mongoose index.d.ts:

dropDatabase(): Promise<any>;
mrhid3f
fonte
-2

Para descartar todos os documentos em uma coleção:

myMongooseModel.collection.drop();

como visto nos testes

Sgnl
fonte