Java 循环遍历 MongoDB 中的文档

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9669151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 05:55:11  来源:igfitidea点击:

Looping through documents in MongoDB

javamongodbloopsdocuments

提问by

I want to loop through documents in MongoDB. Basically here is the situation. I have some JTextfields which i want to populate from MongoDB. So each time the user click on the Next button, a new record must be fetched and display it in the JTextField. Here's my code:

我想遍历 MongoDB 中的文档。基本上情况就是这样。我有一些我想从 MongoDB 填充的 JTextfields。因此,每次用户单击 Next 按钮时,都必须获取一条新记录并将其显示在 JTextField 中。这是我的代码:

public class nextstud implements ActionListener
{
    public void actionPerformed(ActionEvent e) {
        try {
            Mongo s = new Mongo();
            DB db = s.getDB( "omrs1" );
            DBCollection coll = db.getCollection("Student") ;

            DBCursor curs = coll.find();

            if(curs.hasNext()) {
                DBObject o = curs.next();
                String fname = (String) o.get("Firstname") ; 
                String lname = (String) o.get("Lastname") ; 
                String sid = (String) o.get("StudentID") ; 
                String prg = (String) o.get("Programme") ;
                String lvl = (String) o.get("Level") ;

                txtfname.setText(fname) ; 
            }

            btndelstud.setEnabled(true); 
            btnbkstud.setEnabled(true) ;
            btnfwdstud.setEnabled(true);

        } catch (UnknownHostException x) {
            x.printStackTrace();
        } catch (MongoException x) {
            x.printStackTrace();
        }
    }
} // end class

However, it does not work. It only displays the first record each time i press the next button. If i change

但是,它不起作用。每次我按下下一步按钮时,它只显示第一条记录。如果我改变

if(curs.hasNext()) {

to

while(curs.hasNext()) {

It displays only the last record. Help please?

它只显示最后一条记录。请帮忙?

采纳答案by Sean Reilly

As Kevin mentioned, the problem is that you're fetching a new cursor on each button press, so it's always starting over. There are two potential approaches that will fix this problem.

正如凯文所提到的,问题在于您在每次按下按钮时都会获取一个新光标,因此它总是重新开始。有两种可能的方法可以解决这个问题。

  • Fetch the cursor once, and move through it as next is pushed. To do this, you make the cursor a field, and fetch the cursor in the listener's constructor.

    public class Nextstud implements ActionListener {
        private DBCursor curs;
        public Nextstud() {
            Mongo s = new Mongo();
            DB db = s.getDB( "omrs1" );
            DBCollection coll = db.getCollection("Student") ;
    
            curs = coll.find();
        }
    
        public void actionPerformed(ActionEvent e) {
            try {
                if(curs.hasNext()) {
                    DBObject o = curs.next();
                    String fname = (String) o.get("Firstname") ; 
                    String lname = (String) o.get("Lastname") ; 
                    String sid = (String) o.get("StudentID") ; 
                    String prg = (String) o.get("Programme") ;
                    String lvl = (String) o.get("Level") ;
    
                    txtfname.setText(fname) ; 
                }
    
                btndelstud.setEnabled(true); 
                btnbkstud.setEnabled(true) ;
                btnfwdstud.setEnabled(true);
            } catch (UnknownHostException x) {
                x.printStackTrace();
            } catch (MongoException x) {
                x.printStackTrace();
            }
        }
    } // end class
    
  • The next alternative is to keep a count of how many items have been retrieved, and update the cursor's skip count:

    DBCursor foo = coll.find().skip(count).limit(1);
    count++;
    //use one value from the cursor as before
    
  • 获取光标一次,并在按下 next 时移动光标。为此,您将游标设为一个字段,并在侦听器的构造函数中获取游标。

    public class Nextstud implements ActionListener {
        private DBCursor curs;
        public Nextstud() {
            Mongo s = new Mongo();
            DB db = s.getDB( "omrs1" );
            DBCollection coll = db.getCollection("Student") ;
    
            curs = coll.find();
        }
    
        public void actionPerformed(ActionEvent e) {
            try {
                if(curs.hasNext()) {
                    DBObject o = curs.next();
                    String fname = (String) o.get("Firstname") ; 
                    String lname = (String) o.get("Lastname") ; 
                    String sid = (String) o.get("StudentID") ; 
                    String prg = (String) o.get("Programme") ;
                    String lvl = (String) o.get("Level") ;
    
                    txtfname.setText(fname) ; 
                }
    
                btndelstud.setEnabled(true); 
                btnbkstud.setEnabled(true) ;
                btnfwdstud.setEnabled(true);
            } catch (UnknownHostException x) {
                x.printStackTrace();
            } catch (MongoException x) {
                x.printStackTrace();
            }
        }
    } // end class
    
  • 下一个选择是记录已检索的项目数,并更新游标的跳过计数:

    DBCursor foo = coll.find().skip(count).limit(1);
    count++;
    //use one value from the cursor as before
    

The first approach is likely to be slightly faster. Mongo can do this iteration using a single tree traversal (as opposed to many for the second approach).

第一种方法可能会稍微快一些。Mongo 可以使用单个树遍历来完成此迭代(与第二种方法的许多遍历相反)。

The second approach doesn't keep a cursor open between button clicks. This sort of thing is important for scalability on web apps between requests, but might not matter as much with a gui app (especially if the number of concurrent users is smaller).

第二种方法不会在按钮点击之间保持光标打开。这种事情对于请求之间的 Web 应用程序的可伸缩性很重要,但对于 gui 应用程序可能没有那么重要(特别是如果并发用户数较少时)。

Another big advantage of the second approach is that you can go backwards — DBCursordoesn't have a previous()method, so you'll need to use this approach if you ever add a Previous button.

第二种方法的另一大优势是您可以倒退——DBCursor没有previous()方法,因此如果您添加了“上一步”按钮,则需要使用这种方法。

Some other things you should probably do:

您可能应该做的其他一些事情:

  • Add a layer of indirection so that your GUI event handling code and your MongoDB data access code aren't quite so highly coupled. This will save you a bunch of trouble if you move to a different database (perhaps unlikely), or add a previous button that integrates with the same query (perhaps more likely).

  • Remember to close the cursor when you're done with it. DBCursorimplementations leak, and need to be cleaned up with a timeout scheme if you don't explicitly close them. This is especially true if you don't completely iterate through the entire result set. This goes for the Mongo instance as well, but you'll only need a single one of those for the entire application.

  • 添加一个间接层,这样您的 GUI 事件处理代码和您的 MongoDB 数据访问代码就不会那么高耦合。如果您移动到不同的数据库(可能不太可能),或者添加与相同查询集成的上一个按钮(可能更有可能),这将为您省去一大堆麻烦。

  • 完成后请记住关闭光标。DBCursor实现泄漏,如果您没有明确关闭它们,则需要使用超时方案进行清理。如果您没有完全遍历整个结果集,则尤其如此。这也适用于 Mongo 实例,但对于整个应用程序,您只需要其中一个。

回答by Kevin

The problem is that you're fetching a new cursor each time. So it only shows the first record. I assume you have more than one text field, if you want to do all initialization in one function, you'll need to operate on an array of textfields, not a single one. Or, if the intention is to call actionPerformed several times (once for each textField) then you should maintain some state (e.g. the cursor) between calls to actionPerformed. I don't do a lot of GUI programming however, so I'm not sure which is correct based on the code snippet you've provided.

问题是您每次都在获取一个新游标。所以它只显示第一条记录。我假设您有多个文本字段,如果您想在一个函数中完成所有初始化,则需要对一组文本字段进行操作,而不是一个。或者,如果打算多次调用 actionPerformed(每个 textField 调用一次),那么您应该在调用 actionPerformed 之间保持某种状态(例如光标)。但是,我不会进行很多 GUI 编程,因此根据您提供的代码片段,我不确定哪个是正确的。