Sort by array last element mongodb

I was trying to sort documents by last interaction. meta_data.access_times is an array that is updated every time the user interacts and the new date object is appended to the last element of the array. Is there a way to sort by the last element of the array?

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

      

+3


source to share


2 answers


I solve the problem using the $ 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")
        );
    }

      

+2


source


If you don't know if a Push item is set or not (like the user who clicks on it Score ...) you can use $ push and $ sort in order to have an ordered array, you can just sort it by address " find ({userId: yourUseId} .sort ("metadata.access_time.0": - 1).

This solution assumes your array is ordered with $ sort when created / updated: LINK

If you are sure that Push does not require sorting (for example, you are pressing Access_Date for that user), you can $ push and void $ sort using $ operator (tnx Erdenezul). LINK



In theory, you don't need an index in the "access_time" array if find () is only retrieving a few documents. Otherwise, you can simply add the index with {"metadata.access_time.0": -1}.

Good luck!

+2


source







All Articles