【问题标题】:MongoDB and Spring Data - Aggregation with group returns incorrect idMongoDB 和 Spring Data - 与组的聚合返回不正确的 id
【发布时间】:2019-11-20 14:14:25
【问题描述】:

我有以下 MongoDB 文档:

@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@SuperBuilder
@Document(collection = ReasonDocument.COLLECTION)
public class ReasonDocument extends BaseDocument<ObjectId> {
  public static final String COLLECTION = "reasons";

  @Id
  private ObjectId id;
  @Indexed
  private ObjectId ownerId;
  @Indexed
  private LocalDate date;
  private Type type;
  private String reason;
}

我想用最新的date 获取ownerId 的所有行,并另外过滤掉其中的一些行。我为此编写了自定义存储库,我在其中使用带有组语句的聚合:

public class ReasonsRepositoryImpl implements ReasonsRepository {

  private final MongoTemplate mongoTemplate;

  @Autowired
  public ReasonsRepositoryImpl(MongoTemplate mongoTemplate) {
    this.mongoTemplate = mongoTemplate;
  }

  public List<ReasonDocument> findReasons(LocalDate date) {
    final Aggregation aggregation = Aggregation.newAggregation(
      sort(Direction.DESC, "date"),
      group("ownerId")
        .first("id").as("id")
        .first("reason").as("reason")
        .first("type").as("type")
        .first("date").as("date")
        .first("ownerId").as("ownerId"),
      match(Criteria.where("date").lte(date).and("type").is(Type.TYPE_A))
    );
    return mongoTemplate.aggregate(aggregation, "reasons", ReasonDocument.class).getMappedResults();
  }
}

这是智能查询,但不幸的是它在测试时返回损坏的行:

java.lang.AssertionError: 
Expecting:
  <[ReasonDocument(id=5dd5500960483c1b2d974eed, ownerId=5dd5500960483c1b2d974eed, date=2019-05-14, type=TYPA_A, reason=14),
    ReasonDocument(id=5dd5500960483c1b2d974ee8, ownerId=5dd5500960483c1b2d974ee8, date=2019-05-15, type=TYPA_A, reason=1)]>
to contain exactly in any order:
  <[ReasonDocument(id=5dd5500960483c1b2d974eef, ownerId=5dd5500960483c1b2d974ee8, date=2019-05-15, type=TYPA_A, reason=1),
    ReasonDocument(id=5dd5500960483c1b2d974efc, ownerId=5dd5500960483c1b2d974eed, date=2019-05-14, type=TYPA_A, reason=14)]>
elements not found:
  <[ReasonDocument(id=5dd5500960483c1b2d974eef, ownerId=5dd5500960483c1b2d974ee8, date=2019-05-15, type=TYPA_A, reason=1),
    ReasonDocument(id=5dd5500960483c1b2d974efc, ownerId=5dd5500960483c1b2d974eed, date=2019-05-14, type=TYPA_A, reason=14)]>
and elements not expected:
  <[ReasonDocument(id=5dd5500960483c1b2d974eed, ownerId=5dd5500960483c1b2d974eed, date=2019-05-14, type=TYPA_A, reason=14),
    ReasonDocument(id=5dd5500960483c1b2d974ee8, ownerId=5dd5500960483c1b2d974ee8, date=2019-05-15, type=TYPA_A, reason=1)]>

返回的idownerId 相同。
谁能说查询有什么问题?

【问题讨论】:

    标签: java mongodb spring-data-mongodb


    【解决方案1】:

    我不完全确定这是否是问题所在。但是你检查过 mongo 是如何保存 ID 的吗?因为即使您按 ownerID 分组。如果 mongo 已将项目保存在您的 Json 中的 _id 标头下。然后你需要把它称为_id

    例如:如果它看起来像这样

    { “_id”:“2893u4jrnjnwfwpfn”, “名称”:“詹金斯” }

    那么你的 groupBy 应该是 groupBy(_id) 而不是你写的。

    【讨论】:

    • 谢谢!虽然这不是问题的根源 - .first("id").as("id") 应该使用 _id
    【解决方案2】:

    这恰好是 MongoDB 和 ORM 的限制,除非我不知道什么。

    根据文档https://docs.mongodb.com/manual/reference/operator/aggregation/group/,本机 mongo 查询如下所示:

    {
      $group:
        {
          _id: <expression>, // Group By Expression
          <field1>: { <accumulator1> : <expression1> },
          ...
        }
     }
    

    因此,分组本身会创建新的_id - 如果我按ownerId 分组,该值将最终出现在_id 字段中。

    解决这个问题的一种方法是使用:

        .first("_id").as("oldId")
    

    并使用oldId 作为字段创建一个新类型,以后可以使用该字段映射回原始文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 2019-11-27
      相关资源
      最近更新 更多