使用Play Framework 2.5进行ReactiveMongo数据库转储

时间:2016-08-05 08:43:50

标签: scala reactivemongo

我试图将我的mongo数据库转储到json对象中,但因为我对数据库的查询是异步的,所以我遇到了问题。

我的数据库中的每个集合都包含用户数据,每个集合名称都是用户名。

因此,当我想获取所有用户数据时,我会恢复所有集合名称,然后循环遍历它们以逐个恢复每个集合。

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
        }

      } 
    }
  }
}

这种方法有效,但有时即使所有数据尚未恢复,也会成功触发承诺。这是因为我的计数器变量不是一个可靠的解决方案。

有没有办法循环遍历所有用户,查询数据库并等待所有数据恢复,然后才能成功触发承诺?我试图用于理解,但没有找到办法。有没有办法将整个mongo DB转储到一个Json:{ username : data, username : data ..}

2 个答案:

答案 0 :(得分:0)

用户/表术语让我感到困惑,所以我编写了一个新功能,将数据库转储到单个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,集合名称为键。

答案 1 :(得分:0)

如果目标是将数据写入输出流(本地/文件或网络),则会产生副作用。

import java.util.Stack;


public class GetTripletPair {

    /** Set a value for target sum */
    public static final int TARGET_SUM = 32;

    private Stack<Integer> stack = new Stack<Integer>();

    /** Store the sum of current elements stored in stack */
    private int sumInStack = 0;
    private int count =0 ;


    public void populateSubset(int[] data, int fromIndex, int endIndex) {

        /*
        * Check if sum of elements stored in Stack is equal to the expected
        * target sum.
        * 
        * If so, call print method to print the candidate satisfied result.
        */
        if (sumInStack == TARGET_SUM) {
            print(stack);
        }

        for (int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++) {

            if (sumInStack + data[currentIndex] <= TARGET_SUM) {
                ++count;
                stack.push(data[currentIndex]);
                sumInStack += data[currentIndex];

                /*
                * Make the currentIndex +1, and then use recursion to proceed
                * further.
                */
                populateSubset(data, currentIndex + 1, endIndex);
                --count;
                sumInStack -= (Integer) stack.pop();
            }else{
            return;
        }
        }
    }

    /**
    * Print satisfied result. i.e. 15 = 4+6+5
    */

    private void print(Stack<Integer> stack) {
        StringBuilder sb = new StringBuilder();
        sb.append(TARGET_SUM).append(" = ");
        for (Integer i : stack) {
            sb.append(i).append("+");
        }
        System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
    }

    private static final int[] DATA = {4,13,14,15,17};

    public static void main(String[] args) {
        GetAllSubsetByStack get = new GetAllSubsetByStack();
        get.populateSubset(DATA, 0, DATA.length);
    }
}

如果使用JSON序列化包,只需将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 () 替换为BSONDocument(例如JsObject〜&gt; BSONDocument.empty)。

如果从Scala REPL进行测试,粘贴前面的代码后,可以执行以下操作。

Json.obj()