Jak usunąć bazę danych za pomocą Mongoose?

97

Przygotowuję skrypt do tworzenia bazy danych w Node.js i Mongoose. Jak mogę sprawdzić, czy baza danych już istnieje, a jeśli tak, upuść (usuń) ją za pomocą Mongoose?

Nie mogłem znaleźć sposobu, żeby upuścić to z Mongoose.

Yaron Naveh
źródło

Odpowiedzi:

166

Nie ma metody na usunięcie kolekcji z mangusty, najlepsze, co możesz zrobić, to usunąć zawartość jednej z nich:

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

Istnieje jednak sposób na uzyskanie dostępu do natywnego sterownika mongodb javascript, którego można użyć do tego

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

Ostrzeżenie

Zanim spróbujesz, wykonaj kopię zapasową na wypadek, gdyby coś poszło nie tak!

drinchev
źródło
2
kiedy próbuję skorzystać z drugiej opcji, otrzymuję komunikat „nie można odczytać właściwości 'nazwa_kolekcji' niezdefiniowanej”
Yaron Naveh
1
Ponieważ wszystkie kolekcje znajdują się w hash mongoose.connection.collections, możesz po prostu wymienić je dla (collection in mongoose.connection.collections) {mongoose.connection.collections [kolekcja] .drop} ...
smth
3
Masz literówkę - dodatkowy przecinek po funkcji (błąd) ... powinien wyglądać następująco: mongoose.connection.collections ['nazwa_kolekcji']. Drop (funkcja (błąd) {console.log ('kolekcja porzucona') ;});
arxpoetica
3
Czy tylko ja zdałem sobie sprawę, że ta odpowiedź nie dotyczy kwestii usuwania bazy danych. To nie jest prośba o upuszczenie kolekcji, ale prośba o usunięcie bazy danych ...
Joseph Persie
3
„Nie ma metody na usunięcie kolekcji z mangusty”, po pierwsze OP chce usunąć bazę danych, a nie zestawienie, po drugie, odpowiedź @hellslam poniżej działa dobrze.
SCBuergel.eth
79

Mongoose utworzy bazę danych, jeśli jeszcze nie istnieje w połączeniu, więc po nawiązaniu połączenia możesz po prostu zapytać ją, czy coś w niej jest.

Możesz usunąć dowolną bazę danych, z którą jesteś połączony:

var mongoose = require('mongoose');
/* Connect to the DB */
mongoose.connect('mongodb://localhost/mydatabase',function(){
    /* Drop the DB */
    mongoose.connection.db.dropDatabase();
});
hellslam
źródło
1
Próbowałem, mongoose.connection.db.dropDatabase()ale okazało się, że db nadal tam jest? Czy coś mi brakuje?
Freewind
Jeśli później połączysz się z nim, zostanie odtworzony, choć pusty. Czy były w nim jakieś kolekcje po tym, jak go upuściłeś?
hellslam
Czy używasz tego samego połączenia przez cały czas, czy tworzysz wiele połączeń?
hellslam
12
Odkryłem, że dropDatabasewywołanie powinno być umieszczone w wywołaniu zwrotnym connect, as mongoose.connect('...', function() { ...dropDatabase()}).
Freewind
1
dropDatabase wydaje się nie działać w niektórych przypadkach, ale bezpośrednie polecenie mongo nadal może być używane mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function(err, result) { if (err) { console.log(err); } done(); });
farincz
14

Jeśli zmodyfikujesz rozwiązanie @ hellslam w ten sposób, zadziała

Używam tej techniki do usuwania bazy danych po moich testach integracji

//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 przynajmniej zrobiło to dla mnie, więc zdecydowałem się udostępnić =)

Silverfighter
źródło
czy można upuścić db z tym? db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);
chovy
2
To było pomocne, dzięki! Jednak nazwy zmiennych są trochę mylące ... w mongoose.connectrzeczywistości zwracają mongoose. Zamiast conn = mongoose.connect(...)pisać mongoose.connect(...)i wtedy conn = mongooose.connection.
płatny kujon
Nie sądzę, aby ten kod zawsze działał, ponieważ connectjest asynchroniczny. Jeśli więc połączenie nie nastąpi natychmiast, polecenie dropDatabase () nie powiedzie się. Dlatego też inne powyższe rozwiązania zalecały umieszczenie dropDatabasepolecenia w wywołaniu zwrotnym connectinstrukcji lub openmodule obsługi zdarzenia.
Mark Stosberg,
8

Wypróbowałem odpowiedzi @ hellslam i @ silverfighter. Stwierdziłem, że stan wyścigu wstrzymuje moje testy. W moim przypadku przeprowadzam testy mokki, aw funkcji przed testem chcę usunąć całą bazę danych. Oto, co działa w moim przypadku.

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

Możesz przeczytać więcej https://github.com/Automattic/mongoose/issues/1469

zafrani
źródło
7

Zaktualizowana odpowiedź dla 4.6.0+, jeśli wolisz obietnice ( zobacz dokumentację ):

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

Przetestowałem ten kod we własnym kodzie, używając mongoose 4.13.6. Zwróć także uwagę na użycie tej useMongoClientopcji ( patrz dokumentacja ). Dokumenty wskazują:

Domyślna logika połączenia Mongoose jest przestarzała od wersji 4.11.0. Wybierz nową logikę połączeń, korzystając z opcji useMongoClient, ale pamiętaj, aby najpierw przetestować połączenia, jeśli aktualizujesz istniejącą bazę kodu!

Andre M
źródło
5

Problem z innymi rozwiązaniami polega na tym, że polegają one na ponownym uruchomieniu aplikacji, jeśli chcesz, aby indeksy znów działały.

Na moje potrzeby (tj. Możliwość przeprowadzenia testu jednostkowego nuków wszystkich kolekcji, a następnie odtworzenia ich wraz z ich indeksami), w końcu zaimplementowałem to rozwiązanie:

Opiera się to na bibliotekach underscore.js i async.js w celu zebrania indeksów w parellel. Jeśli jesteś przeciwko tej bibliotece, może to zostać cofnięte , ale zostawiam to jako ćwiczenie dla programisty.

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
źródło
4

Aby opróżnić określoną kolekcję w bazie danych:

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

Uwaga:

  1. Wybierz model odnoszący się do konkretnego schematu (schemat zbioru, który chcesz usunąć).
  2. Ta operacja nie spowoduje usunięcia nazwy kolekcji z bazy danych.
  3. Spowoduje to usunięcie wszystkich dokumentów w kolekcji.
duński
źródło
4

To działa dla mnie od Mongoose v4.7.0:

mongoose.connection.dropDatabase();
user3344977
źródło
4

Najlepszy sposób na upuszczenie bazy danych w Mongoose zależy od używanej wersji Mongoose. Jeśli używasz wersji Mongoose w wersji 4.6.4 lub nowszej, ta metoda dodana w tej wersji prawdopodobnie będzie działać dobrze:

mongoose.connection.dropDatabase();

W starszych wersjach ta metoda nie istniała. Zamiast tego miałeś użyć bezpośredniego połączenia z MongoDB:

mongoose.connection.db.dropDatabase();

Jeśli jednak zostanie to uruchomione zaraz po utworzeniu połączenia z bazą danych, prawdopodobnie po cichu zakończy się niepowodzeniem. Jest to związane z faktem, że połączenie jest w rzeczywistości asynchroniczne i nie jest jeszcze konfigurowane w momencie wykonania polecenia. Zwykle nie stanowi to problemu w przypadku innych wywołań Mongoose, takich jak .find()kolejka do momentu otwarcia połączenia, a następnie uruchomienia.

Jeśli spojrzysz na kod źródłowy dropDatabase()dodanego skrótu, zobaczysz, że został on zaprojektowany, aby rozwiązać dokładnie ten problem. Sprawdza, czy połączenie jest otwarte i gotowe. Jeśli tak, natychmiast uruchamia polecenie. Jeśli nie, rejestruje polecenie do uruchomienia po otwarciu połączenia z bazą danych.

Niektóre z powyższych sugestii zalecają zawsze umieszczanie dropDatabasepolecenia w programie openobsługi. Ale to działa tylko w przypadku, gdy połączenie nie jest jeszcze otwarte.

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;
};

Oto prosta wersja powyższej logiki, której można używać we wcześniejszych wersjach 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
źródło
2

Mongoose 4.6.0+:

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

Przekazywanie oddzwonienia do połączenia nie będzie już działać:

TypeError: nie można odczytać właściwości „commandsTakeWriteConcern” o wartości null

Rayjax
źródło
1
connectzwraca obietnicę, więc możesz dodać .then((connection) => { ... });ją do mongoose.connect. Zobacz: 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
źródło
0

Ponieważ metoda remove jest zdeprecjonowana w bibliotece mongoose, możemy użyć funkcji deleteMany bez przekazanych parametrów.

Model.deleteMany();

Spowoduje to usunięcie całej zawartości tego konkretnego Modelu, a Twoja kolekcja będzie pusta.

SAYAM.S SANGHVI
źródło
0

Aby upuścić wszystkie dokumenty w kolekcji:

await mongoose.connection.db.dropDatabase();

Ta odpowiedź jest oparta na pliku mongoose index.d.ts:

dropDatabase(): Promise<any>;
mrhid3f
źródło
-2

Aby usunąć wszystkie dokumenty w kolekcji:

myMongooseModel.collection.drop();

jak widać w testach

Sgnl
źródło