2016-08-05 25 views
0

Ich versuche, meine Mongo-Datenbank in ein JSON-Objekt zu entleeren, aber weil meine Abfragen an die Datenbank asynchron sind, habe ich Probleme.ReactiveMongo Datenbank-Dump mit Play Framework 2.5

Jede Sammlung in meiner Datenbank enthält Benutzerdaten und jeder Sammlungsname ist ein Benutzername.

Also, wenn ich alle meine Benutzerdaten erhalten möchte, ich alle Sammlungsnamen wiederherstellen und dann über sie hinweg, um jede Sammlung einzeln wiederherzustellen.

Diese Art funktioniert, aber manchmal wird das Versprechen erfolgreich ausgelöst, obwohl alle Daten noch nicht wiederhergestellt wurden. Dies liegt daran, dass meine Zählervariable keine zuverlässige Lösung ist.

Gibt es eine Möglichkeit, alle Benutzer zu durchlaufen, die Datenbank abzufragen und zu warten, bis alle Daten wiederhergestellt sind, bevor das Versprechen erfolgreich ausgelöst wurde? Ich habe versucht, es zu verstehen, aber ich habe keinen Weg gefunden, es zu tun. Gibt es eine Möglichkeit, eine ganze Mongo-DB in einen JSON zu schreiben: { username : data, username : data ..}?

+0

Für solche DB-Admin-Aufgabe, ich glaube nicht, Codierung etwas neues mit einem Treiber ist der richtige Weg. Das Dienstprogramm 'mongodump' kann die Daten direkt als JSON erhalten. Abgesehen davon würde ich vorschlagen, dass Sie sich die Dokumentation ansehen, um zu verstehen, wie [Dokument mit ReactiveMongo zu finden] (und was?) ist die [JSON-Serialisierung] (http://reactivemongo.org/releases/0.11/documentation/json/overview.html) für. – cchantep

+0

Ich muss dies in Scala tun, weil ich eine API schreibe. Die Daten, die ich wiederherstelle, werden also an andere zu behandelnde Funktionen gesendet. Ich benutze JSON Serialisierung, aber ich sehe nicht, wie man es verwendet, um die gesamte Datenbank auf einmal und nicht Sammlung durch Sammlung zu erhalten. –

+0

"Dumping" ist "nur" ein spezieller Fall, um (alle) das Dokument einiger Dokumente zu finden (ein Anwendungsfall wird wiederum üblicherweise von dedizierten db-Admin-Tools gehandhabt). – cchantep

Antwort

0

Die Benutzer/Tabellen Terminologie hat mich verwirrt, so schrieb ich eine neue Funktion, die eine Datenbank in eine einzige JsObject Dumps.

// helper function to find all documents inside a collection c 
// and return them as a single JsArray 
def getDocs(c: JSONCollection)(implicit ec: ExecutionContext) = c.find(Json.obj()).cursor[JsObject]().jsArray() 

def dumpToJsObject(db: DefaultDB)(implicit ec: ExecutionContext): Future[JsObject] = { 
    // get a list of all collections in the db 
    val collectionNames = db.collectionNames 
    val collections = collectionNames.map(_.map(db.collection[JSONCollection](_))) 

    // each entry is a tuple collectionName -> content (as JsArray) 
    val namesToDocs = collections.flatMap { 
    colls => Future.sequence(colls.map(c => getDocs(c).map(c.name -> _))) 
    } 

    // convert to a single JsObject 
    namesToDocs.map(JsObject(_)) 
} 

Ich habe es noch nicht getestet (ich werde tun, so später), aber diese Funktion zumindest sollten Sie die allgemeine Idee geben. Sie erhalten die Liste aller Sammlungen in der Datenbank. Für jede Sammlung führen Sie eine Abfrage durch, um alle Dokumente in dieser Sammlung abzurufen. Die Liste der Dokumente wird in eine JsArray konvertiert, und schließlich werden alle Sammlungen zu einem einzigen JsObject mit den Auflistungsnamen als Schlüssel zusammengesetzt.

+0

Ich versuche, dies zu implementieren, aber ich bekomme einen Fehler mit dem Future.sequence Teil, NotInferedM [Future [NotInferedA]]. Ich habe nie die Future.sequence-Funktion verwendet, so dass ich nicht wirklich weiß, was das bedeutet. –

+0

Wie bereits angedeutet, könntest du dir Tutorials oder Bücher darüber ansehen, wie [Scala Futures] (http://docs.scala-lang.org/overviews/core/futures.html) funktioniert – cchantep

+0

@Carsten konnte ich nicht bekommen Dein Code funktioniert, aber ich habe meine Lösung darauf basiert. Die Funktion Future.sequence hat mein Problem am Ende gelöst. Ich habe eine Liste [Future [JsObject]] erstellt und Future.sequence verwendet, um sie in Future [List [JsObject]] umzuwandeln. Dann habe ich einfach darüber geloopt. –

0

Wenn das Ziel ist, die Daten in einen Ausgabestrom (lokal/Datei oder Netzwerk) mit Nebenwirkungen zu schreiben.

import scala.concurrent.{ ExecutionContext, Future } 
import reactivemongo.bson.BSONDocument 
import reactivemongo.api.{ Cursor, MongoDriver, MongoConnection } 

val mongoUri = "mongodb://localhost:27017/my_db" 

val driver = new MongoDriver 
val maxDocs = Int.MaxValue // max per collection 

// Requires to have an ExecutionContext in the scope 
// (e.g. `import scala.concurrent.ExecutionContext.Implicits.global`) 
def dump()(implicit ec: ExecutionContext): Future[Unit] = for { 
    uri <- Future.fromTry(MongoConnection.parseURI(mongoUri)) 
    con = driver.connection(uri) 
    dn <- Future(uri.db.get) 
    db <- con.database(dn) 
    cn <- db.collectionNames 
    _ <- Future.sequence(cn.map { collName => 
    println(s"Collection: $collName") 

    db.collection(collName).find(BSONDocument.empty). // findAll 
     cursor[BSONDocument]().foldWhile({}, maxDocs) { (_, doc) => 
     // Replace println by appropriate side-effect 
     Cursor.Cont(println(s"- ${BSONDocument pretty doc}")) 
     } 
    }) 
} yield() 

Wenn mit dem JSON Serialisierung Pack verwenden, ersetzen nur BSONDocument mit JsObject (z BSONDocument.empty ~>Json.obj()).

Wenn Sie von der Scala REPL testen, nachdem Sie den vorherigen Code eingefügt haben, kann er wie folgt ausgeführt werden.

dump().onComplete { 
    case result => 
    println(s"Dump result: $result") 
    //driver.close() 
} 
+0

Ich habe Carsten als die Lösung, wie er zuerst antwortete und beide Ihre Antworten sind ähnlich –