2012-06-15 6 views
12

Друзья!Итерация над большой коллекцией в MongoDB по данным весны

Я использую MongoDB в проекте java через данные весны. Я использую интерфейсы репозитория для доступа к данным в коллекциях. Для некоторой обработки мне нужно перебрать все элементы коллекции. Я могу использовать метод репозитория fetchAll, но он всегда возвращает ArrayList.

Однако предполагается, что одна из коллекций будет большой - до 1 миллиона записей по меньшей мере на несколько килобайт. Я полагаю, что я не должен использовать fetchAll в таких случаях, но я не мог найти ни удобных методов, возвращающих некоторый итератор (который может позволить частично получить выборку), ни удобные методы с обратными вызовами.

Я видел только поддержку для получения таких коллекций на страницах. Интересно, является ли это единственным способом работы с такими коллекциями?

+0

Вы можете использовать 'предел()' функцию, чтобы ограничить функцию получить данные в кусках –

+0

Я не знаком с используемой структурой, но мне было бы очень странно, если бы у нее не было обертки для курсоров MongoDB. Вы уверены, что то, что вы получаете, это 'ArrayList', а не обычная реализация« List », которая обтекает курсор? – thkala

+2

да, конечно - я только что зарегистрировал свой findAll(). GetClass() для коллекции около 3 миллионов, и я думаю, что увидел java.util.ArrayList ... –

ответ

17

Поздний отклик, но, возможно, это поможет кому-то в будущем.) Данные Spring не предоставляют никакого API для обертывания Mongo DB Cursor возможностей. Он использует его в пределах find методов, но всегда возвращает завершенный список объектов. Варианты использования Монго API напрямую или использовать Spring Data Paging API, что-то вроде этого:

 final int pageLimit = 300; 
     int pageNumber = 0; 
     Page<T> page = repository.findAll(new PageRequest(pageNumber, pageLimit)); 
     while (page.hasNextPage()) { 
      processPageContent(page.getContent()); 
      page = repository.findAll(new PageRequest(++pageNumber, pageLimit)); 
     } 
     // process last page 
     processPageContent(page.getContent()); 
+8

Я просто хотел еще перезвонить и сказать, что для больших наборов данных, вы также должны держаться подальше от Paging API, так как перед тем, как строить каждую страницу, нужно пройти всю коллекцию. Это становится дорогостоящим. Придерживайтесь использования Mongo API напрямую. –

+0

@ShawnBush Вы уверены в этом? – javadev

3

Другой способ:

do{ 
    page = repository.findAll(new PageRequest(pageNumber, pageLimit)); 
    pageNumber++; 

}while (!page.isLastPage()); 
7

Использование MongoTemplate :: поток(), как, вероятно, наиболее подходящий Java обертка для DBCursor

6

вы все еще можете использовать mongoTemplate для доступа к коллекции и просто использовать DBCursor:

 DBCollection collection = mongoTemplate.getCollection("boundary"); 
    DBCursor cursor = collection.find();   
    while(cursor.hasNext()){ 
     DBObject obj = cursor.next(); 
     Object object = obj.get("polygons"); 
     .. 
     ... 
    } 
0

Вы можете попробовать использовать способ DBCursor следующим образом:

DBObject query = new BasicDBObject(); //setup the query criteria 
    query.put("method", method); 
    query.put("ctime", (new BasicDBObject("$gte", bTime)).append("$lt", eTime)); 

    logger.debug("query: {}", query); 

    DBObject fields = new BasicDBObject(); //only get the needed fields. 
    fields.put("_id", 0); 
    fields.put("uId", 1); 
    fields.put("ctime", 1); 

    DBCursor dbCursor = mongoTemplate.getCollection("collectionName").find(query, fields); 

    while (dbCursor.hasNext()){ 
     DBObject object = dbCursor.next(); 
     logger.debug("object: {}", object); 
     //do something. 
    } 
1

Streams, как курсор:

@Query("{}") 
Stream<Alarm> findAllByCustomQueryAndStream(); 

Таким образом, для большого количества данных, которые вы можете передавать их и обрабатывать построчно без ограничения памяти

Смежные вопросы