I'm having an issue with an old aggregation query.
I have a mongo collection which has many documents containing information about credits / gifts given / awarded to our users.
Currently I am able to run an Aggregated Query to get all the users who have received a credit / gift within the last x number of days and sum the total value of those credits for each user. However, my problem is that now I want to project more fields for my mapping class which I am unable to do.
Here is the document in Mongo
_id: ObjectId("61c36a8a21047124c4181271"),
transactionId: UUID("6fbf536e-7a53-442c-9615-53e32362608b"),
userId: 'xxxxx',
transactionMessage: 'Account credited with: 1',
transactionType: 'CREDIT',
transactionAction: 'GIFT',
inComingPaymentFromUserId: 'xxxx',
awardForContentId : "abcd123242"
transactionAmount: Decimal128("1"),
customMessage: "blah'",
createdDate: ISODate("2021-12-22T18:12:26.812Z"),
lastUpdatedAt: ISODate("2021-12-22T18:12:26.812Z"),
I can run a aggregation which gives me the correct mapping like so:
Aggregation agg = Aggregation.newAggregation(match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range))
.andOperator(Criteria.where("transactionAction").is("GIFT"))), sort(Sort.Direction.DESC, "createdDate"),
group("userId").sum("transactionAmount").as("totalValueAwarded"),
skip((long) pageable.getPageNumber() * pageable.getPageSize()),
limit(pageable.getPageSize()));
mongoTemplate.aggregate(agg, Transaction.class, RecentlyRewardedUsers.class).getMappedResults();
For Context my mapped RecentlyRewarded.class looks like this:
@Getter
@Setter
public class RecentlyRewardedUsers {
@Field("userId")
private String userId;
private String totalValueAwarded;
}
And correctly the data is mapped to the two fields when the above aggregation runs.
Now, I find I need to add more fields to my RecentlyRewarded class:
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RecentlyRewardedUsers {
@Field("id")
@Id
private String userId;
private BigDecimal totalValueAwarded;
private String awardForContentId; //THIS IS THE NEW FIELD I've ADDED
}
I thought I would be able to just add the new field "awardforContentId" to my group query and it would be correctly mapped but that is not happening:
Aggregation agg = Aggregation.newAggregation(match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range))
.andOperator(Criteria.where("transactionAction").is("GIFT"))), sort(Sort.Direction.DESC, "createdDate"),
group("userId", "awardForContentId").sum("transactionAmount").as("totalValueAwarded"),
skip((long) pageable.getPageNumber() * pageable.getPageSize()),
limit(pageable.getPageSize()));
mongoTemplate.aggregate(agg, Transaction.class, RecentlyRewardedUsers.class).getMappedResults();
What happens is that my userId field in my POJO is now set to:
{"userId": "auth0|61b9e2f7d1fc9f0071d508f1", "awardForContentId": "637b98a85dde3949fbb4314f"}
and the awardForContentId in my class is null.
I have also tried just adding the awardForConentId to the project operation like so:
Aggregation agg = Aggregation.newAggregation(match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range))
.andOperator(Criteria.where("transactionAction").is("GIFT"))), sort(Sort.Direction.DESC, "createdDate"),
group("userId").sum("transactionAmount").as("totalValueAwarded"),
project("userId", "totalValueAwarded", "awardForContentId"),
skip((long) pageable.getPageNumber() * pageable.getPageSize()),
limit(pageable.getPageSize()));
However that results in the following error:
Method threw 'java.lang.IllegalArgumentException' exception.
Invalid reference 'awardForContentId'!
What am I doing stupid here?
Many thanks
When you group by multiple fields, the result will look something like this.
{
"_id": {
"userId": ,
"awardForContentId": ,
},
"transactionAmount":
}
So, you have to project it correctly to match you Java class.
Aggregation agg = Aggregation.newAggregation(
match(
Criteria.where("createdDate").gt(LocalDate.now().minusDays(range))
.andOperator(Criteria.where("transactionAction").is("GIFT"))
),
sort(Sort.Direction.DESC, "createdDate"),
group("userId", "awardForContentId").sum("transactionAmount").as("totalValueAwarded"),
project()
.and("_id.userId").as("userId")
.and("_id.awardForContentId").as("awardForContentId")
.andInclude("totalValueAwarded")
skip((long) pageable.getPageNumber() * pageable.getPageSize()),
limit(pageable.getPageSize())
);
You can remove @Field("id") @Id
from the returning class.