将流式集合写入文件Java-Mongo

时间:2018-05-25 08:58:48

标签: java mongodb

我有一台运行Monogdb的服务器,它也有一个名为mycoll的集合。新文档将不断插入到集合中。我的目的是拥有一个本地文件,其中包含该集合的所有文档的副本。我目前的做法如下:

String host = "myHost";
int port = 3717;
String user = "user";
String password = "pass";
String databaseName = "dbName";
String collectionName = "mycoll";

MongoCredential credential = MongoCredential.createCredential(user, databaseName, password.toCharArray());
MongoClient mongoClient = new MongoClient(new ServerAddress(host, port), Arrays.asList(credential));
MongoDatabase database = mongoClient.getDatabase(databaseName);
MongoCollection<Document> collection = database.getCollection(collectionName);
FindIterable<Document> cursor = collection.find();

String path = "./outputData.txt";


while(cursor.iterator().hasNext()){

        try(FileWriter fw = new FileWriter(path, true);
                BufferedWriter bw = new BufferedWriter(fw);
                PrintWriter out = new PrintWriter(bw))
        {
                out.println(cursor.iterator().next());
        } catch (IOException e) {
                System.out.println("Error writing to file.");
        }

}

我知道我可以创建一个缓冲区来存储数据并在之后编写它,但是最大的问题仍然没有解决:文档是逐个访问的。因此,我的问题是:我如何一次访问多个文档才能在./outputData.txt中写入?

4 个答案:

答案 0 :(得分:2)

简单来说,只需通过调用MongoCursor“一次”返回iterator(),因为这就是您需要做的全部。

然后非常简单地在循环“外部”创建文件句柄。唯一真正属于“循环内部”的是实际的游标迭代和写作。

try {    

  MongoCursor<Document> cursor = collection.find().iterator();
  String path = "./outputData.txt";

  PrintWriter out = new PrintWriter(
    new BufferedWriter(new FileWriter(path, true))
  );

  while(cursor.hasNext()){
    out.println(cursor.next().toJson());
  }

  out.flush();            // flush to ensure writes
  out.close();            // close the handle when done

} catch (IOException e) {
  System.out.println("Error writing to file.");
}

完成游标后,只需关闭返回的文件描述符即可。

您真正需要注意的是,您不“创建”文件描述符或继续在循环内“重新打开”。这是你曾经做过的事情,然后只需通过任何方式“写出”每次迭代。

作为完整列表,您可以在默认端口上针对本地MongoDB运行代码,而无需身份验证。添加选项以根据需要进行更改,但这是所需的“基本”代码

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Application {

    public static void main(String[] args) {

        PrintWriter out  = null;
        MongoClient mongoClient = null;

        try {

            mongoClient = new MongoClient();
            MongoDatabase db = mongoClient.getDatabase("test");
            MongoCollection<Document> collection = db.getCollection("sample");

            out = new PrintWriter(
                    new BufferedWriter(new FileWriter("output.txt"))
            );

            // Clear collection and insert data
            collection.deleteMany(new Document());
            collection.insertMany(Arrays.asList(
                    new Document("a", 1),
                    new Document("a", 2),
                    new Document("a", 3)
            ));

            MongoCursor<Document> cursor = collection.find().iterator();

            while ( cursor.hasNext() ) {
                out.println(cursor.next().toJson());
                //System.out.println(cursor.next().toJson());
            }

            out.flush();

        } catch(Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (out != null) {
                out.close();
            }
            if (mongoClient != null) {
                mongoClient.close();
            }
        }
    }
}

在每次运行时创建一个新文件,并输出插入到集合中的文档。

为您提供如下文件:

{ "_id" : { "$oid" : "5b0bd9576a6bfa1f30e6c320" }, "a" : 1 }
{ "_id" : { "$oid" : "5b0bd9576a6bfa1f30e6c321" }, "a" : 2 }
{ "_id" : { "$oid" : "5b0bd9576a6bfa1f30e6c322" }, "a" : 3 }

答案 1 :(得分:0)

您还可以使用 Spring Integration + MongoDB solution

  

23.4 MongoDB入站通道适配器

     

MongoDb入站通道适配器是一个读取的轮询使用者   来自MongoDb的数据并将其作为消息有效负载发送。

<int-mongodb:inbound-channel-adapter id="mongoInboundAdapter"
       channel="replyChannel"
       query="{'name' : 'Bob'}"
       entity-class="java.lang.Object"
       auto-startup="false">
      <int:poller fixed-rate="100"/>
</int-mongodb:inbound-channel-adapter>

说明

MongoDB Inbound Channel Adapter可以连续查询您的MongoDB数据库,然后处理信息以执行您想要执行的操作。

您可以在文档中找到几个示例。

我希望这会对你有所帮助。

答案 2 :(得分:0)

您可以使用.batchsize()批量读取进行优化。 使用游标检索数据时,可以使用 batchSize 子句指定每个操作中获取的行数。

示例:

FindIterable<Document> collection = database.getCollection(collectionName)
.find()
.batchSize(arraySize);
//if you want to read 10 documents at once, 
 //set arraySize to 10.. so on

for(Document doc : collection) {
      //  save to file
     }

请注意,batchSize运算符实际上并不向程序返回一个数组 - 它只是控制每次网络往返中检索的文档数。从程序的角度来看,这一切都发生在“幕后”。希望这个帮助

您可以在https://docs.mongodb.com/manual/reference/method/cursor.batchSize/

了解有关batchsize的更多信息

答案 3 :(得分:0)

我认为,你需要很多触发器。 MongoDB对触发器没有任何支持,但有些人已经推出了自己的&#34;使用一些技巧。这里的关键是oplog。

在副本集中运行MongoDB时,所有MongoDB操作都会记录到操作日志(称为oplog)。 oplog基本上只是对数据所做修改的运行列表。副本通过侦听此oplog上的更改然后在本地应用更改来设置功能。<​​/ p>

您还可以阅读有关tailable游标的信息。 此外,您可以从正在进行的项目中获得相同问题的帮助:
https://github.com/deftlabs/mongo-java-tailable-cursor

相关问题