Mongodb выбрать все поля сгруппировать по одному полю и отсортировать по другому полю

5

У нас есть сбор "сообщение" со следующими полями

_id |   messageId |  chainId | createOn

1   |       1     |    A     | 155
2   |       2     |    A     | 185
3   |       3     |    A     | 225
4   |       4     |    B     | 226
5   |       5     |    C     | 228
6   |       6     |    B     | 300

Мы хотим выбрать все поля документа со следующими критериями

  • distict по полю 'chainId'
  • порядок (сортировка) по 'createdOn' в порядке desc

поэтому ожидаемый результат

_id |   messageId |  chainId | createOn

3   |       3     |    A     | 225
5   |       5     |    C     | 228
6   |       6     |    B     | 300

Мы используем spring -data в нашем java-приложении. Я пытался пойти разными подходами, пока ничего не помогло. Можно ли достичь выше с помощью одного запроса?

Теги:
aggregation-framework
spring-data-mongodb
mapreduce

4 ответа

7
Лучший ответ

То, что вы хотите, - это то, что может быть достигнуто с помощью структуры агрегации. Основная форма (полезная для других):

db.collection.aggregate([

    // Group by the grouping key, but keep the valid values
    { "$group": {
        "_id": "$chainId",
        "docId": { "$first": "$_id" },
        "messageId": { "$first": "$messageId" },
        "createOn": { "$first": "$createdOn" }
    }},

    // Then sort
    { "$sort": { "createOn": -1 } }

])

Итак, чтобы "группы" находились в разных значениях "messageId", принимая граничные значения $first для каждого из других полей. Альтернативно, если вы хотите, чтобы наибольший использовали вместо $last, но для самой маленькой или самой большой по строкам это, вероятно, делает сначала нужно $sort, иначе просто используйте $min и $max, если вся строка не важно.

Дополнительную информацию об использовании см. в документации MongoDB aggregate(), а также в JavaDocs и SpringData Mongo для более широкого использования агрегатного метода и возможных помощников.

  • 0
    Благодарю. Это мне тоже помогло. Ура !!
4

вот решение с использованием драйвера Java MongoDB

    final MongoClient mongoClient = new MongoClient();
    final DB db = mongoClient.getDB("mstreettest");
    final DBCollection collection = db.getCollection("message");

    final BasicDBObject groupFields = new BasicDBObject("_id", "$chainId");
    groupFields.put("docId", new BasicDBObject("$first", "$_id"));
    groupFields.put("messageId", new BasicDBObject("$first", "$messageId"));
    groupFields.put("createOn", new BasicDBObject("$first", "$createdOn"));

    final DBObject group = new BasicDBObject("$group", groupFields);

    final DBObject sortFields = new BasicDBObject("createOn", -1);
    final DBObject sort = new BasicDBObject("$sort", sortFields);

    final DBObject projectFields = new BasicDBObject("_id", 0);
    projectFields.put("_id", "$docId");
    projectFields.put("messageId", "$messageId");
    projectFields.put("chainId", "$_id");
    projectFields.put("createOn", "$createOn");
    final DBObject project = new BasicDBObject("$project", projectFields);

    final AggregationOutput aggregate = collection.aggregate(group, sort, project);

и результат будет:

{ "_id" : 5 , "messageId" : 5 , "createOn" : { "$date" : "2014-04-23T04:45:45.173Z"} , "chainId" : "C"}
{ "_id" : 4 , "messageId" : 4 , "createOn" : { "$date" : "2014-04-23T04:12:25.173Z"} , "chainId" : "B"}
{ "_id" : 1 , "messageId" : 1 , "createOn" : { "$date" : "2014-04-22T08:29:05.173Z"} , "chainId" : "A"}

Я попробовал его с SpringData Mongo, и он не работал, когда я группирую его по цепочке (java.lang.NumberFormatException: для строки ввода: "C" ) было исключением

0

вот решение, использующее springframework.data.mongodb:

Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.group("chainId"),
                Aggregation.sort(new Sort(Sort.Direction.ASC, "createdOn"))
              );
AggregationResults<XxxBean> results = mongoTemplate.aggregate(aggregation, "collection_name", XxxBean.class);
0

Заменить эту строку:

final DBObject group = new BasicDBObject("$group", groupFields);

с этим:

final DBObject group = new BasicDBObject("_id", groupFields);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню