Удалить дубликаты элементов на основе условия - PullRequest
0 голосов
/ 10 января 2020

У меня есть список ниже, в котором есть повторяющиеся элементы

Я хочу удалить все дубликаты из списка на основе свойства версии и даты

Это означает, что при наличии дублирующего элемента я получить тот, у которого есть activ состояния, если никто не имеет actif состояния, то я получаю тот с недавней датой

[
   {
      "_id" : ObjectId("5e1832df02f04352705457dd"),
      "product":"1",
      "version":{
         "state":"Actif",
         "name":"1.0.0"
      },
      "createdDate":"01/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705457ff"),
      "product":"1",
      "version":{
         "state":"A faire",
         "name":"3.0.0"
      },
      "createdDate":"01/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705457ee"),
      "product":"1",
      "version":{
         "state":"Archiver",
         "name":"2.0.0"
      },
      "createdDate":"02/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705457gg"),
      "product":"2",
      "version":null,
      "createdDate":"01/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705457yy"),
      "product":"2",
      "version":{
         "state":"Archiver",
         "name":"2.0.0"
      },
      "createdDate":"02/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705455ss"),
      "product":"3",
      "version":{
         "state":"Archiver",
         "name":"2.0.0"
      },
      "createdDate":"01/01/2020"
   }
]

Вывод должен выглядеть так:

[
   {
      "_id" : ObjectId("5e1832df02f04352705457dd"),
      "product":"1",
      "version":{
         "state":"Actif",
         "name":"1.0.0"
      },
      "createdDate":"01/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705457yy"),
      "product":"2",
      "version":{
         "state":"Archiver",
         "name":"2.0.0"
      },
      "createdDate":"02/01/2020"
   },
   {
      "_id" : ObjectId("5e1832df02f04352705455ss"),
      "product":"3",
      "version":{
         "state":"Archiver",
         "name":"2.0.0"
      },
      "createdDate":"01/01/2020"
   }
]

public List<Product> search() {
    final Query query = new Query().with(new Sort(new Order(Direction.DESC, "createdDate")));
    return mongoOperations.find(query, Product.class);
}

Как мы можем сделать это?

Ответы [ 2 ]

0 голосов
/ 13 января 2020

Агрегирование с использованием совместимых операторов Spring Data 2.2 и MongoDB 3.4.

MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "spr_test");

Aggregation agg = newAggregation(
    project("product", "version")
        .and(Concat.valueOf(SubstrCP.valueOf("createdDate").substringCP(6, 4))
                .concat("-")
                .concatValueOf(SubstrCP.valueOf("createdDate").substringCP(3, 2))
                .concat("-")
                .concatValueOf(SubstrCP.valueOf("createdDate").substringCP(0, 2)) )
        .as("createdDate"),
    group("product")
        .push("$$ROOT").as("details")
        .push("createdDate").as("createdDates"),
    facet(   
        project("details")
            .and(Size.lengthOfArray("details")).as("arrSize"),
        match(where("arrSize").is(new Integer(1))))
    .as("c1")
    .and(
        match(where("details.version.state").is("Actif" )), 
        project()
            .and(filter("details")
                .as("d")
                .by(Eq.valueOf("d.version.state").equalToValue("Actif" )))
            .as("details"))
    .as("c2")
    .and(
        project("details", "createdDates")
            .and(Size.lengthOfArray("details")).as("arrSize"),
        match(where("arrSize").gt(new Integer(1))
            .and("details.version.state").ne("Actif")),
        project()
            .and(filter("details")
                .as("d")
                .by(Eq.valueOf("d.createdDate").equalTo(Max.maxOf("createdDates"))))
            .as("details"))
    .as("c3"),
    project()
        .and(arrayOf("c1").concat("c2").concat("c3"))
        .as("result"),
    unwind("result"),
    project()
        .and(arrayOf("result.details").elementAt(0)).as("result")
);

AggregationResults<Document> results = mongoOps.aggregate(agg, "test", Document.class);

results.forEach(System.out::println);
0 голосов
/ 10 января 2020

Вам необходимо использовать aggregate метод.

Java код

Не тестировалось! Если AggregationOperation предполагает реализовать метод toDocument, измените все BasicDBObject на Document.

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

Aggregation aggregation = newAggregation(
        sort(Sort.Direction.ASC, "product", "version", "createdDate"), 
        group("product").last("$$ROOT").as("root"),
        sort(Sort.Direction.ASC, "_id"),
        //$replaceRoot
        );

return mongoTemplate.aggregate(aggregation, Product.class, Product.class).getMappedResults();

Оболочка MongoDB

db.Product.aggregate([
  {
    $sort: {
      product: 1,
      version: -1,
      createdDate: -1
    }
  },
  {
    $group: {
      _id: "$product",
      root: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $sort: {
      _id: 1
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $arrayElemAt: [
          {
            $concatArrays: [
              {
                $filter: {
                  input: "$root",
                  cond: {
                    $eq: [
                      "$$this.version.state",
                      "Actif"
                    ]
                  }
                }
              },
              [
                {
                  $arrayElemAt: [
                    "$root",
                    0
                  ]
                }
              ]
            ]
          },
          0
        ]
      }
    }
  }
])

MongoPlayground

...