2016-08-05 7 views
0

mongoデータベースをjsonオブジェクトにダンプしようとしていますが、データベースに対するクエリが非同期であるため、問題が発生しています。ReactiveMongoデータベースフレームをPlay Framework 2.5でダンプする

私のデータベースの各コレクションにはユーザーデータが含まれており、各コレクション名はユーザー名です。

私はすべてのコレクションの名前を回復してから、各コレクションを1つずつ回復するためにそれらの上にループします。

def databaseDump(prom : Promise[JsObject]) = { 
    for{ 
     dbUsers <- getUsers 
    } yield dbUsers 

var rebuiltJson = Json.obj() 
var array = JsArray() 
res.map{ users => 
    users.map{ userNames => 
    if(userNames.size == 0){ 
     prom failure new Throwable("Empty database") 
    } 
    var counter = 0 
    userNames.foreach { username => 
     getUserTables(username).map { tables => 
     /* Add data to array*/ 
      ... 
     counter += 1 
     if(counter == userNames.size){ 
      /*Add data to new json*/ 
      ... 
      prom success rebuiltJson 
     } 

     } 
    } 
    } 
} 

このように動作しますが、すべてのデータがまだ復元されていなくても、約束が正常に開始されることがあります。これは、私のカウンタ変数が信頼できる解決策ではないという事実によるものです。

すべてのユーザーをループし、データベースにクエリを送信し、すべてのデータが回復するのを待ってから、約束をうまく起動させる方法はありますか?私は理解のために使用しようとしましたが、それを行う方法が見つかりませんでした。 1つのJsonに全体のDBをダンプする方法はありますか:{ username : data, username : data ..}

+0

このようなdb管理タスクでは、私はドライバを使って新しいものをコーディングするのが正しい方法だとは思わない。ユーティリティ 'mongodump 'はJSONとして直接データを取得できます。それ以外に、[ReactiveMongoを使ってドキュメントを見つける](http://reactivemongo.org/releases/0.11/documentation/tutorial/find-documents.html)を理解するためのドキュメントを見てみることをお勧めします。のための[JSONシリアライゼーション](http://reactivemongo.org/releases/0.11/documentation/json/overview.html)です。 – cchantep

+0

私はAPIを書いているので、スカラでこれを行う必要があります。したがって、回復したデータは、処理される他の機能に送信されます。私はJSONシリアライゼーションを使用していますが、コレクション全体ではなく、一度にデータベース全体を取得する方法はわかりません。 –

+0

"Dumping"は、いくつかのドキュメントのドキュメントを検索する特定のケースです(ユースケースは通常、専用のDB管理ツールで処理されます)。 – cchantep

答えて

0

ユーザー/テーブルの用語が混乱していたので、データベースを1つのJsObjectにダンプする新しい関数を書きました。

// 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(_)) 
} 

私は(私が後でそうだろう)まだそれをテストしていませんが、この機能は、少なくともあなたの一般的なアイデアを与える必要があります。データベース内のすべてのコレクションのリストを取得します。コレクションごとに、そのコレクション内のすべての文書を取得するためのクエリを実行します。ドキュメントのリストはJsArrayに変換され、最後にすべてのコレクションはキーとしてコレクション名を持つ単一のJsObjectで構成されます。

+0

これを実装しようとしていますが、Future.sequenceの部分、NotInferedM [Future [NotInferedA]]でエラーが発生しています。私はFuture.sequence関数を使用したことがないので、これが何を意味するのか分かりません。 –

+0

[Scala Futures](http://docs.scala-lang.org/overviews/core/futures.html)がどのように機能しているかについてのチュートリアルや書籍をご覧ください。 – cchantep

+0

@Carsten私は手に入れられませんでしたあなたのコードは動作しますが、私はそれをベースにしています。 Future.sequence関数は私の問題を最後に解決したものです。私はList [Future [JsObject]]を作成し、それをFuture [List [JsObject]]に変換するためにFuture.sequenceを使用しました。それから私は単にそれを繰り返した。 –

0

目的がデータを出力ストリーム(ローカル/ファイルまたはネットワーク)に、副作用で書き込むことである場合。

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() 

だけJsObject(例えばBSONDocument.empty〜>Json.obj())でBSONDocumentを置き換え、JSONのシリアライズパックを使用している場合。

Scala REPLからテストする場合、前のコードを貼り付けた後、次のように実行できます。

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

私は答えとしてCarstenを答えとして答えます。あなたの答えはどちらも似ています –

関連する問題