Условные / max mon go запросы с использованием Spring mongoTemplate - PullRequest
0 голосов
/ 29 февраля 2020

У меня есть сотни таких записей в коллекции mongodb:

{
    "city" : "London",
    "eventTime": 1582866000,
    "createdTime": 1582900145,
    "eventDetails: {
        ...
    }
}

Это соответствует Event классу

public class Event {
    private String city;
    private long eventTime;
    private long createdTime;
    private EventDetails eventDetails;

    //getters and setters
}

- eventTime (все значения времени в локальной эпохе / unix время) всегда будет равняться часу
- createdTime используется в качестве контроля версий (больше createdTime, более поздняя версия этой информации)
- не используется update / upsert, как я использую для хранения более старой информации

Я хочу иметь возможность запросить что-то вроде этого:

1) с учетом временной метки версии - вернуть список объектов (весь объект) ) для каждого city, для каждого eventTime, где отметка времени наиболее близка к (этаж или потолок) createdTime
2) то же самое, что и 1), но для max (createTime) - для каждого city и каждого eventTime

По существу - будет много дубликатов для каждого city, для каждого eventTime из-за нескольких версий, и мне нужна только указанная мной версия и последняя версия

Я пытаюсь выполнить эти два запроса, используя mongoTemplate в java (весна понедельник go) Я пытался возиться с Query, Aggregation, AggregationOperator.Max, но, похоже, ничего не работает

Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("city").is(city)),
Aggregation.match(Criteria.where("eventTime").gte(startTime).lte(endTime)),
Aggregation.group("$$ROOT").max("createdTime").as("createdTime")
);
AggregationResults<Event> groupResults = mongoTemplate.aggregate(aggregation, "collection-name", Event.class);
result = groupResults.getMappedResults();

пример данных и ожидаемые результаты: https://script.google.com/d/1JgOFzdVBGiueYpXT8u-R6AJpbX6FxxtkVwq_NpLraZeS19Pxh6zmnATb/edit?usp=sharing

Я также пытался выполнить эти запросы в оболочке mongodb, но также не увенчался успехом, похоже, но не возвращает желаемую структуру объекта

db.getCollection('collection-name').aggregate([{$group:{_id : "$$ROOT", createdTime : {$max:"$createdTime"}}}])

1 Ответ

1 голос
/ 29 февраля 2020

Макс

db.collection.aggregate([
  {
    $group: {
      _id: {
        city: "$city",
        eventTime: "$eventTime"
      },
      max: {
        $max: "$createdTime"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      max_events: {
        $filter: {
          input: "$data",
          cond: {
            $eq: [
              "$max",
              "$$this.createdTime"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$max_events"
  },
  {
    $replaceRoot: {
      newRoot: "$max_events"
    }
  }
])

MongoPlayground

MongoTemplate

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

Aggregation agg = Aggregation.newAggregation(
    group("city", "eventTime").max("createdTime").as("max").push("$$ROOT").as("data"),
    project().and(new AggregationExpression() {
        @Override
        public Document toDocument(AggregationOperationContext context) {
            return new Document("$filter",
                    new Document("input", "$data")
                         .append("cond", new Document("$eq", Arrays.asList("$max", "$$this.createdTime"))));
        }
    }).as("max_events"),
    unwind("max_events"),
    replaceRoot("max_events")
);

AggregationResults<Event> events = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Event.class), Event.class);

for(Event ev: events) {
    System.out.println(ev);
}

Ближайший

db.collection.aggregate([
  {
    $group: {
      _id: {
        city: "$city",
        eventTime: "$eventTime"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      closest: {
        $reduce: {
          input: "$data",
          initialValue: {
            $arrayElemAt: [
              "$data",
              0
            ]
          },
          in: {
            $cond: [
              {
                $lt: [
                  {
                    $abs: {
                      $subtract: [
                        "$$this.eventTime",
                        "$$this.createdTime"
                      ]
                    }
                  },
                  {
                    $abs: {
                      $subtract: [
                        "$$value.eventTime",
                        "$$value.createdTime"
                      ]
                    }
                  }
                ]
              },
              "$$this",
              "$$value"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$closest"
  },
  {
    $replaceRoot: {
      newRoot: "$closest"
    }
  }
])

MongoPlayground

MongoTemplate

Aggregation agg = Aggregation.newAggregation(
    group("city", "eventTime").push("$$ROOT").as("data"),
    project().and(new AggregationExpression() {
        @Override
        public Document toDocument(AggregationOperationContext context) {
            return new Document("$reduce",
                    new Document("input", "$data")
                     .append("initialValue", new Document("$arrayElemAt", Arrays.asList("$data", 0)))
                     .append("in", new Document("$cond", Arrays.asList(
                            new Document("$lt",  Arrays.asList(
                                new Document("$abs", new Document("$subtract", Arrays.asList("$$this.eventTime", "$$this.createdTime"))), 
                                new Document("$abs", new Document("$subtract", Arrays.asList("$$value.eventTime", "$$value.createdTime"))))), 
                            "$$this",
                            "$$value"))));
        }
    }).as("closest"),
    unwind("closest"),
    replaceRoot("closest")
);

AggregationResults<Event> events = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Event.class), Event.class);

for(Event ev: events) {
    System.out.println(ev);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...