3

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")
        ] }
9
  • Well we seem to be missing any representation of what your document actually looks like. Care to share it with us? Commented Jun 22, 2017 at 6:59
  • @NeilLunn updated Commented Jun 22, 2017 at 7:05
  • So the "last" is always appended and therefore the "latest"? Normally is but just checking. Commented Jun 22, 2017 at 7:06
  • @NeilLunn yeah! Commented Jun 22, 2017 at 7:11
  • What do you expect as output? That group is throwing me as it's not clear what to expect. Mostly since it's not valid. How about showing whole documents ( just 2 or 3 ) and what you expect to get as your query result. That would be clearer to interpret than your query attempt. The date part I already understand. Commented Jun 22, 2017 at 7:16

2 Answers 2

2

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")
        );
    }
Sign up to request clarification or add additional context in comments.

Comments

1

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!

7 Comments

Add latest access into 0th element with push position 0 would be nice
@Erdenezul do you think is not a viable solution?
in order to avoid sort, pushing latest element at index 0 is more efficient.
@Erdenezul oh you are right, $position can be used but I have just posted a general solution that work for any scenario.
could you revise your answer with my idea, then I can vote up your answer
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.