根据条件删除重复项目

Delete duplicates items based on condition

我有以下包含重复元素的列表

我想根据版本和日期从列表中删除所有重复项属性

这意味着,如果有一个重复的元素,我会得到一个具有状态 actif 的元素,如果没有一个有状态 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);
}

我们该怎么做?

您需要使用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 shell

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

使用 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);