FazoM
FazoM

Reputation: 4956

MongoDB and Spring Data - Aggregation with group returns incorrect id

I have following MongoDB document:

@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;
}

I would like to get all rows for ownerId with latest date and additionally filter some of them out. I wrote custom repository for that, where I use aggregation with a group statement:

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();
  }
}

It is smart query but unfortunately it returns corrupted rows while testing:

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)]>

The id returned is the same as ownerId.
Could anyone say what is wrong with the query?

Upvotes: 0

Views: 1317

Answers (2)

FazoM
FazoM

Reputation: 4956

This happens to be limitation of MongoDB and ORM, unless I'm not aware of something.

According to documentation https://docs.mongodb.com/manual/reference/operator/aggregation/group/, native mongo query looks like this:

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

So grouping itself creates new _id - if I group by ownerId that value will end up in _id field.

One way of solving this is by using:

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

and creating a new type with oldId as a field that can be later used to map back to original Document.

Upvotes: 0

AiSirachcha21
AiSirachcha21

Reputation: 119

Im not entirely sure whether or not this may be the problem. But did you check how mongo has saved the ID? because even if you're grouping by ownerID. IF mongo has saved the item under the _id header in your Json. Then you need to refer it as _id

Ex: If it looks like this

{ "_id" : "2893u4jrnjnwfwpfn", "name" : "Jenkins" }

then your groupBy should be groupBy(_id) and not what you've written.

Upvotes: 1

Related Questions