I was trying to sort documents by last interaction. meta_data.access_times is an array that update every time when user interacts and new date object append to the last element of the array. Is there any way to sort by array's last element?
Attempt 1 :
private Aggregation makeQuery(String userId) { return newAggregation( match(Criteria.where("user_id").is(userId)), sort(Sort.Direction.DESC, "$meta_data.access_times"), group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id").and("access_times", "$meta_data.access_times")) ); }
Attempt 2 :
private Aggregation makeQuery(String userId) { return newAggregation( match(Criteria.where("user_id").is(user_id)), group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id")).max("$meta_data.access_times").as("access_time"), sort(Sort.Direction.DESC, "access_time") ); }
sample meta_data array in document
"meta_data" : { "access_times" : [ ISODate("2017-06-20T14:04:14.910Z"), ISODate("2017-06-22T06:27:32.210Z"), ISODate("2017-06-22T06:27:35.326Z"), ISODate("2017-06-22T06:31:28.048Z"), ISODate("2017-06-22T06:36:19.664Z"), ISODate("2017-06-22T06:37:00.164Z") ] }
2 Answers
Answers 1
I solves the problem by using $unwind operation.
private Aggregation makeQuery(String userId) { return newAggregation( match(Criteria.where("user_id").is(userId)), unwind("$meta_data.access_times"), group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id")).max("$meta_data.access_times").as("access_time"), sort(Sort.Direction.DESC, "access_time") ); }
Answers 2
When you don't know if the element to Push is Ordered or not (for example, an User that is pushing him Score...) you can use $push and $sort in order to have an ordered array, then you can just sort by "find({userId:yourUseId}.sort("metadata.access_time.0":-1).
This solution suppose your array are Ordered with $sort at creation/update time: LINK
When you are sure that the Push don't need a sort (for example you are Pushing a Access_Date for that User) you can $push and void $sort by using $operator (tnx Erdenezul). LINK
In theory you don't need an Index on the Array "access_time" if the find() is fetching only fews documents. Otherwise you can just add an index with {"metadata.access_time.0": -1}.
Good Luck!
0 comments:
Post a Comment